blob: 0efc3f2fdde4ce612be4e02557b2fc28c1b663df [file] [log] [blame]
Nirav Shah52d85aa2018-04-26 14:03:00 +05301/*
Srinivas Girigowdaa9877462019-02-20 11:20:38 -08002 * Copyright (c) 2011-2019 The Linux Foundation. All rights reserved.
Nirav Shah52d85aa2018-04-26 14:03:00 +05303 *
4 * Permission to use, copy, modify, and/or distribute this software for
5 * any purpose with or without fee is hereby granted, provided that the
6 * above copyright notice and this permission notice appear in all
7 * copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16 * PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#include <qdf_atomic.h> /* qdf_atomic_inc, etc. */
20#include <qdf_lock.h> /* qdf_os_spinlock */
21#include <qdf_time.h> /* qdf_system_ticks, etc. */
22#include <qdf_nbuf.h> /* qdf_nbuf_t */
23#include <qdf_net_types.h> /* QDF_NBUF_TX_EXT_TID_INVALID */
24
Ashish Kumar Dhanotiya94ffbd12019-08-08 18:00:59 +053025#include "queue.h" /* TAILQ */
Nirav Shah52d85aa2018-04-26 14:03:00 +053026#ifdef QCA_COMPUTE_TX_DELAY
27#include <enet.h> /* ethernet_hdr_t, etc. */
28#include <ipv6_defs.h> /* ipv6_traffic_class */
29#endif
30
31#include <ol_txrx_api.h> /* ol_txrx_vdev_handle, etc. */
32#include <ol_htt_tx_api.h> /* htt_tx_compl_desc_id */
33#include <ol_txrx_htt_api.h> /* htt_tx_status */
34
35#include <ol_ctrl_txrx_api.h>
36#include <cdp_txrx_tx_delay.h>
37#include <ol_txrx_types.h> /* ol_txrx_vdev_t, etc */
38#include <ol_tx_desc.h> /* ol_tx_desc_find, ol_tx_desc_frame_free */
39#ifdef QCA_COMPUTE_TX_DELAY
40#include <ol_tx_classify.h> /* ol_tx_dest_addr_find */
41#endif
42#include <ol_txrx_internal.h> /* OL_TX_DESC_NO_REFS, etc. */
43#include <ol_osif_txrx_api.h>
44#include <ol_tx.h> /* ol_tx_reinject */
45#include <ol_tx_send.h>
46
47#include <ol_cfg.h> /* ol_cfg_is_high_latency */
48#include <ol_tx_sched.h>
49#ifdef QCA_SUPPORT_SW_TXRX_ENCAP
50#include <ol_txrx_encap.h> /* OL_TX_RESTORE_HDR, etc */
51#endif
52#include <ol_tx_queue.h>
53#include <ol_txrx.h>
54#include <pktlog_ac_fmt.h>
55#include <cdp_txrx_handle.h>
Jeff Johnson8feaa632018-12-07 11:56:02 -080056#include <wlan_reg_services_api.h>
Tiger Yue40e7832019-04-25 10:46:53 +080057#include "qdf_hrtimer.h"
Nirav Shah52d85aa2018-04-26 14:03:00 +053058
Nirav Shah2b3843e2019-10-24 15:10:46 +053059/* High/Low tx resource count in percentage */
60/* Set default high threashold to 15% */
61#ifndef TX_RESOURCE_HIGH_TH_IN_PER
62#define TX_RESOURCE_HIGH_TH_IN_PER 15
63#endif
64
65/* Set default low threshold to 5% */
66#ifndef TX_RESOURCE_LOW_TH_IN_PER
67#define TX_RESOURCE_LOW_TH_IN_PER 5
68#endif
69
Nirav Shah52d85aa2018-04-26 14:03:00 +053070#ifdef QCA_HL_NETDEV_FLOW_CONTROL
71static u16 ol_txrx_tx_desc_alloc_table[TXRX_FC_MAX] = {
72 [TXRX_FC_5GH_80M_2x2] = 2000,
73 [TXRX_FC_2GH_40M_2x2] = 800,
74};
75#endif /* QCA_HL_NETDEV_FLOW_CONTROL */
76
77/* tx filtering is handled within the target FW */
78#define TX_FILTER_CHECK(tx_msdu_info) 0 /* don't filter */
79
80u_int16_t
81ol_tx_desc_pool_size_hl(struct cdp_cfg *ctrl_pdev)
82{
83 uint16_t desc_pool_size;
84 uint16_t steady_state_tx_lifetime_ms;
85 uint16_t safety_factor;
86
87 /*
88 * Steady-state tx latency:
89 * roughly 1-2 ms flight time
90 * + roughly 1-2 ms prep time,
91 * + roughly 1-2 ms target->host notification time.
92 * = roughly 6 ms total
93 * Thus, steady state number of frames =
94 * steady state max throughput / frame size * tx latency, e.g.
95 * 1 Gbps / 1500 bytes * 6 ms = 500
96 *
97 */
98 steady_state_tx_lifetime_ms = 6;
99
100 safety_factor = 8;
101
102 desc_pool_size =
103 ol_cfg_max_thruput_mbps(ctrl_pdev) *
104 1000 /* 1e6 bps/mbps / 1e3 ms per sec = 1000 */ /
105 (8 * OL_TX_AVG_FRM_BYTES) *
106 steady_state_tx_lifetime_ms *
107 safety_factor;
108
109 /* minimum */
110 if (desc_pool_size < OL_TX_DESC_POOL_SIZE_MIN_HL)
111 desc_pool_size = OL_TX_DESC_POOL_SIZE_MIN_HL;
112
113 /* maximum */
114 if (desc_pool_size > OL_TX_DESC_POOL_SIZE_MAX_HL)
115 desc_pool_size = OL_TX_DESC_POOL_SIZE_MAX_HL;
116
117 return desc_pool_size;
118}
119
120#ifdef CONFIG_TX_DESC_HI_PRIO_RESERVE
121
122/**
123 * ol_tx_hl_desc_alloc() - Allocate and initialize a tx descriptor
124 * for a HL system.
125 * @pdev: the data physical device sending the data
126 * @vdev: the virtual device sending the data
127 * @msdu: the tx frame
128 * @msdu_info: the tx meta data
129 *
130 * Return: the tx decriptor
131 */
132static inline
133struct ol_tx_desc_t *ol_tx_hl_desc_alloc(struct ol_txrx_pdev_t *pdev,
134 struct ol_txrx_vdev_t *vdev,
135 qdf_nbuf_t msdu,
136 struct ol_txrx_msdu_info_t *msdu_info)
137{
138 struct ol_tx_desc_t *tx_desc = NULL;
139
140 if (qdf_atomic_read(&pdev->tx_queue.rsrc_cnt) >
141 TXRX_HL_TX_DESC_HI_PRIO_RESERVED) {
142 tx_desc = ol_tx_desc_hl(pdev, vdev, msdu, msdu_info);
143 } else if (qdf_nbuf_is_ipv4_pkt(msdu) == true) {
144 if ((QDF_NBUF_CB_GET_PACKET_TYPE(msdu) ==
145 QDF_NBUF_CB_PACKET_TYPE_DHCP) ||
146 (QDF_NBUF_CB_GET_PACKET_TYPE(msdu) ==
147 QDF_NBUF_CB_PACKET_TYPE_EAPOL)) {
148 tx_desc = ol_tx_desc_hl(pdev, vdev, msdu, msdu_info);
149 ol_txrx_info("Got tx desc from resv pool\n");
150 }
151 }
152 return tx_desc;
153}
154
155#elif defined(QCA_HL_NETDEV_FLOW_CONTROL)
156bool ol_tx_desc_is_high_prio(qdf_nbuf_t msdu)
157{
158 enum qdf_proto_subtype proto_subtype;
159 bool high_prio = false;
160
161 if (qdf_nbuf_is_ipv4_pkt(msdu) == true) {
162 if ((QDF_NBUF_CB_GET_PACKET_TYPE(msdu) ==
163 QDF_NBUF_CB_PACKET_TYPE_DHCP) ||
164 (QDF_NBUF_CB_GET_PACKET_TYPE(msdu) ==
165 QDF_NBUF_CB_PACKET_TYPE_EAPOL))
166 high_prio = true;
167 } else if (QDF_NBUF_CB_GET_PACKET_TYPE(msdu) ==
168 QDF_NBUF_CB_PACKET_TYPE_ARP) {
169 high_prio = true;
170 } else if ((QDF_NBUF_CB_GET_PACKET_TYPE(msdu) ==
171 QDF_NBUF_CB_PACKET_TYPE_ICMPv6)) {
172 proto_subtype = qdf_nbuf_get_icmpv6_subtype(msdu);
173 switch (proto_subtype) {
174 case QDF_PROTO_ICMPV6_NA:
175 case QDF_PROTO_ICMPV6_NS:
176 high_prio = true;
177 default:
178 high_prio = false;
179 }
180 }
181 return high_prio;
182}
183
184static inline
185struct ol_tx_desc_t *ol_tx_hl_desc_alloc(struct ol_txrx_pdev_t *pdev,
186 struct ol_txrx_vdev_t *vdev,
187 qdf_nbuf_t msdu,
188 struct ol_txrx_msdu_info_t *msdu_info)
189{
190 struct ol_tx_desc_t *tx_desc =
191 ol_tx_desc_hl(pdev, vdev, msdu, msdu_info);
192
193 if (!tx_desc)
194 return NULL;
195
196 qdf_spin_lock_bh(&pdev->tx_mutex);
197 /* return if TX flow control disabled */
198 if (vdev->tx_desc_limit == 0) {
199 qdf_spin_unlock_bh(&pdev->tx_mutex);
200 return tx_desc;
201 }
202
203 if (!qdf_atomic_read(&vdev->os_q_paused) &&
204 (qdf_atomic_read(&vdev->tx_desc_count) >= vdev->queue_stop_th)) {
205 /*
206 * Pause normal priority
207 * netdev queues if tx desc limit crosses
208 */
209 pdev->pause_cb(vdev->vdev_id,
210 WLAN_STOP_NON_PRIORITY_QUEUE,
211 WLAN_DATA_FLOW_CONTROL);
212 qdf_atomic_set(&vdev->os_q_paused, 1);
213 } else if (ol_tx_desc_is_high_prio(msdu) && !vdev->prio_q_paused &&
214 (qdf_atomic_read(&vdev->tx_desc_count)
215 == vdev->tx_desc_limit)) {
216 /* Pause high priority queue */
217 pdev->pause_cb(vdev->vdev_id,
218 WLAN_NETIF_PRIORITY_QUEUE_OFF,
219 WLAN_DATA_FLOW_CONTROL_PRIORITY);
220 vdev->prio_q_paused = 1;
221 }
222 qdf_spin_unlock_bh(&pdev->tx_mutex);
223
224 return tx_desc;
225}
226
227#else
228
229static inline
230struct ol_tx_desc_t *ol_tx_hl_desc_alloc(struct ol_txrx_pdev_t *pdev,
231 struct ol_txrx_vdev_t *vdev,
232 qdf_nbuf_t msdu,
233 struct ol_txrx_msdu_info_t *msdu_info)
234{
235 struct ol_tx_desc_t *tx_desc = NULL;
236
237 tx_desc = ol_tx_desc_hl(pdev, vdev, msdu, msdu_info);
238 return tx_desc;
239}
240#endif
241
Nirav Shah52d85aa2018-04-26 14:03:00 +0530242static inline uint16_t
243ol_txrx_rsrc_threshold_lo(int desc_pool_size)
244{
245 int threshold_low;
246
Nirav Shah52d85aa2018-04-26 14:03:00 +0530247 /* always maintain a 5% margin of unallocated descriptors */
Nirav Shah2b3843e2019-10-24 15:10:46 +0530248 threshold_low = ((TX_RESOURCE_LOW_TH_IN_PER) *
249 desc_pool_size) / 100;
Nirav Shah52d85aa2018-04-26 14:03:00 +0530250
251 return threshold_low;
252}
253
254static inline uint16_t
255ol_txrx_rsrc_threshold_hi(int desc_pool_size)
256{
257 int threshold_high;
258 /* when freeing up descriptors, keep going until
259 * there's a 15% margin
260 */
Nirav Shah2b3843e2019-10-24 15:10:46 +0530261 threshold_high = ((TX_RESOURCE_HIGH_TH_IN_PER) *
262 desc_pool_size) / 100;
Nirav Shah52d85aa2018-04-26 14:03:00 +0530263
264 return threshold_high;
265}
Nirav Shah52d85aa2018-04-26 14:03:00 +0530266
267void ol_tx_init_pdev(ol_txrx_pdev_handle pdev)
268{
269 uint16_t desc_pool_size, i;
270
271 desc_pool_size = ol_tx_desc_pool_size_hl(pdev->ctrl_pdev);
272
273 qdf_atomic_init(&pdev->tx_queue.rsrc_cnt);
274 qdf_atomic_add(desc_pool_size, &pdev->tx_queue.rsrc_cnt);
275
276 pdev->tx_queue.rsrc_threshold_lo =
277 ol_txrx_rsrc_threshold_lo(desc_pool_size);
278 pdev->tx_queue.rsrc_threshold_hi =
279 ol_txrx_rsrc_threshold_hi(desc_pool_size);
280
281 for (i = 0 ; i < OL_TX_MAX_TXQ_GROUPS; i++)
282 qdf_atomic_init(&pdev->txq_grps[i].credit);
283
284 ol_tx_target_credit_init(pdev, desc_pool_size);
285}
286
287#ifdef QCA_SUPPORT_SW_TXRX_ENCAP
288static inline int ol_tx_encap_wrapper(struct ol_txrx_pdev_t *pdev,
289 ol_txrx_vdev_handle vdev,
290 struct ol_tx_desc_t *tx_desc,
291 qdf_nbuf_t msdu,
292 struct ol_txrx_msdu_info_t *tx_msdu_info)
293{
294 if (OL_TX_ENCAP(vdev, tx_desc, msdu, tx_msdu_info) != A_OK) {
295 qdf_atomic_inc(&pdev->tx_queue.rsrc_cnt);
296 ol_tx_desc_frame_free_nonstd(pdev, tx_desc, 1);
297 if (tx_msdu_info->peer) {
298 /* remove the peer reference added above */
299 ol_txrx_peer_release_ref(tx_msdu_info->peer,
300 PEER_DEBUG_ID_OL_INTERNAL);
301 }
302 return -EINVAL;
303 }
304
305 return 0;
306}
307#else
308static inline int ol_tx_encap_wrapper(struct ol_txrx_pdev_t *pdev,
309 ol_txrx_vdev_handle vdev,
310 struct ol_tx_desc_t *tx_desc,
311 qdf_nbuf_t msdu,
312 struct ol_txrx_msdu_info_t *tx_msdu_info)
313{
314 /* no-op */
315 return 0;
316}
317#endif
318
319/**
320 * parse_ocb_tx_header() - Function to check for OCB
321 * @msdu: Pointer to OS packet (qdf_nbuf_t)
322 * @tx_ctrl: TX control header on a packet and extract it if present
323 *
324 * Return: true if ocb parsing is successful
325 */
Nirav Shah575282c2018-07-08 22:48:00 +0530326#ifdef WLAN_FEATURE_DSRC
Nirav Shah52d85aa2018-04-26 14:03:00 +0530327#define OCB_HEADER_VERSION 1
328static bool parse_ocb_tx_header(qdf_nbuf_t msdu,
329 struct ocb_tx_ctrl_hdr_t *tx_ctrl)
330{
Srinivas Girigowdaa9877462019-02-20 11:20:38 -0800331 qdf_ether_header_t *eth_hdr_p;
Nirav Shah52d85aa2018-04-26 14:03:00 +0530332 struct ocb_tx_ctrl_hdr_t *tx_ctrl_hdr;
333
334 /* Check if TX control header is present */
Srinivas Girigowdaa9877462019-02-20 11:20:38 -0800335 eth_hdr_p = (qdf_ether_header_t *)qdf_nbuf_data(msdu);
Nirav Shah52d85aa2018-04-26 14:03:00 +0530336 if (eth_hdr_p->ether_type != QDF_SWAP_U16(ETHERTYPE_OCB_TX))
337 /* TX control header is not present. Nothing to do.. */
338 return true;
339
340 /* Remove the ethernet header */
Srinivas Girigowdaa9877462019-02-20 11:20:38 -0800341 qdf_nbuf_pull_head(msdu, sizeof(qdf_ether_header_t));
Nirav Shah52d85aa2018-04-26 14:03:00 +0530342
343 /* Parse the TX control header */
344 tx_ctrl_hdr = (struct ocb_tx_ctrl_hdr_t *)qdf_nbuf_data(msdu);
345
346 if (tx_ctrl_hdr->version == OCB_HEADER_VERSION) {
347 if (tx_ctrl)
348 qdf_mem_copy(tx_ctrl, tx_ctrl_hdr,
349 sizeof(*tx_ctrl_hdr));
350 } else {
351 /* The TX control header is invalid. */
352 return false;
353 }
354
355 /* Remove the TX control header */
356 qdf_nbuf_pull_head(msdu, tx_ctrl_hdr->length);
357 return true;
358}
Nirav Shah575282c2018-07-08 22:48:00 +0530359#else
360static bool parse_ocb_tx_header(qdf_nbuf_t msdu,
361 struct ocb_tx_ctrl_hdr_t *tx_ctrl)
362{
363 return true;
364}
365#endif
Nirav Shah52d85aa2018-04-26 14:03:00 +0530366
367/**
368 * ol_txrx_mgmt_tx_desc_alloc() - Allocate and initialize a tx descriptor
369 * for management frame
370 * @pdev: the data physical device sending the data
371 * @vdev: the virtual device sending the data
372 * @tx_mgmt_frm: the tx management frame
373 * @tx_msdu_info: the tx meta data
374 *
375 * Return: the tx decriptor
376 */
377struct ol_tx_desc_t *
378ol_txrx_mgmt_tx_desc_alloc(
379 struct ol_txrx_pdev_t *pdev,
380 struct ol_txrx_vdev_t *vdev,
381 qdf_nbuf_t tx_mgmt_frm,
382 struct ol_txrx_msdu_info_t *tx_msdu_info)
383{
384 struct ol_tx_desc_t *tx_desc;
385
386 tx_msdu_info->htt.action.tx_comp_req = 1;
387 tx_desc = ol_tx_desc_hl(pdev, vdev, tx_mgmt_frm, tx_msdu_info);
388 return tx_desc;
389}
390
391/**
392 * ol_txrx_mgmt_send_frame() - send a management frame
393 * @vdev: virtual device sending the frame
394 * @tx_desc: tx desc
395 * @tx_mgmt_frm: management frame to send
396 * @tx_msdu_info: the tx meta data
397 * @chanfreq: download change frequency
398 *
399 * Return:
400 * 0 -> the frame is accepted for transmission, -OR-
401 * 1 -> the frame was not accepted
402 */
403int ol_txrx_mgmt_send_frame(
404 struct ol_txrx_vdev_t *vdev,
405 struct ol_tx_desc_t *tx_desc,
406 qdf_nbuf_t tx_mgmt_frm,
407 struct ol_txrx_msdu_info_t *tx_msdu_info,
408 uint16_t chanfreq)
409{
410 struct ol_txrx_pdev_t *pdev = vdev->pdev;
411 struct ol_tx_frms_queue_t *txq;
412 int status = 1;
413
414 /*
415 * 1. Look up the peer and queue the frame in the peer's mgmt queue.
416 * 2. Invoke the download scheduler.
417 */
418 txq = ol_tx_classify_mgmt(vdev, tx_desc, tx_mgmt_frm, tx_msdu_info);
419 if (!txq) {
420 /* TXRX_STATS_MSDU_LIST_INCR(vdev->pdev, tx.dropped.no_txq,
421 * msdu);
422 */
423 qdf_atomic_inc(&pdev->tx_queue.rsrc_cnt);
424 ol_tx_desc_frame_free_nonstd(vdev->pdev, tx_desc,
425 1 /* error */);
426 goto out; /* can't accept the tx mgmt frame */
427 }
428 /* Initialize the HTT tx desc l2 header offset field.
429 * Even though tx encap does not apply to mgmt frames,
430 * htt_tx_desc_mpdu_header still needs to be called,
431 * to specifiy that there was no L2 header added by tx encap,
432 * so the frame's length does not need to be adjusted to account for
433 * an added L2 header.
434 */
435 htt_tx_desc_mpdu_header(tx_desc->htt_tx_desc, 0);
436 if (qdf_unlikely(htt_tx_desc_init(
437 pdev->htt_pdev, tx_desc->htt_tx_desc,
438 tx_desc->htt_tx_desc_paddr,
439 ol_tx_desc_id(pdev, tx_desc),
440 tx_mgmt_frm,
441 &tx_msdu_info->htt, &tx_msdu_info->tso_info, NULL, 0)))
442 goto out;
443 htt_tx_desc_display(tx_desc->htt_tx_desc);
444 htt_tx_desc_set_chanfreq(tx_desc->htt_tx_desc, chanfreq);
445
446 ol_tx_enqueue(vdev->pdev, txq, tx_desc, tx_msdu_info);
447 ol_tx_sched(vdev->pdev);
448 status = 0;
449out:
450 if (tx_msdu_info->peer) {
451 /* remove the peer reference added above */
452 ol_txrx_peer_release_ref(tx_msdu_info->peer,
453 PEER_DEBUG_ID_OL_INTERNAL);
454 }
455
456 return status;
457}
458
459/**
460 * ol_tx_hl_base() - send tx frames for a HL system.
461 * @vdev: the virtual device sending the data
462 * @tx_spec: indicate what non-standard transmission actions to apply
463 * @msdu_list: the tx frames to send
464 * @tx_comp_req: tx completion req
Tiger Yue40e7832019-04-25 10:46:53 +0800465 * @call_sched: will schedule the tx if true
Nirav Shah52d85aa2018-04-26 14:03:00 +0530466 *
467 * Return: NULL if all MSDUs are accepted
468 */
469static inline qdf_nbuf_t
470ol_tx_hl_base(
471 ol_txrx_vdev_handle vdev,
472 enum ol_tx_spec tx_spec,
473 qdf_nbuf_t msdu_list,
Tiger Yue40e7832019-04-25 10:46:53 +0800474 int tx_comp_req,
475 bool call_sched)
Nirav Shah52d85aa2018-04-26 14:03:00 +0530476{
477 struct ol_txrx_pdev_t *pdev = vdev->pdev;
478 qdf_nbuf_t msdu = msdu_list;
479 struct ol_txrx_msdu_info_t tx_msdu_info;
480 struct ocb_tx_ctrl_hdr_t tx_ctrl;
481 htt_pdev_handle htt_pdev = pdev->htt_pdev;
482
483 tx_msdu_info.tso_info.is_tso = 0;
484
485 /*
486 * The msdu_list variable could be used instead of the msdu var,
487 * but just to clarify which operations are done on a single MSDU
488 * vs. a list of MSDUs, use a distinct variable for single MSDUs
489 * within the list.
490 */
491 while (msdu) {
492 qdf_nbuf_t next;
493 struct ol_tx_frms_queue_t *txq;
494 struct ol_tx_desc_t *tx_desc = NULL;
495
496 qdf_mem_zero(&tx_ctrl, sizeof(tx_ctrl));
497 tx_msdu_info.peer = NULL;
498 /*
499 * The netbuf will get stored into a (peer-TID) tx queue list
500 * inside the ol_tx_classify_store function or else dropped,
501 * so store the next pointer immediately.
502 */
503 next = qdf_nbuf_next(msdu);
504
505 tx_desc = ol_tx_hl_desc_alloc(pdev, vdev, msdu, &tx_msdu_info);
506
507 if (!tx_desc) {
508 /*
509 * If we're out of tx descs, there's no need to try
510 * to allocate tx descs for the remaining MSDUs.
511 */
512 TXRX_STATS_MSDU_LIST_INCR(pdev, tx.dropped.host_reject,
513 msdu);
514 return msdu; /* the list of unaccepted MSDUs */
515 }
516
517 /* OL_TXRX_PROT_AN_LOG(pdev->prot_an_tx_sent, msdu);*/
518
Nirav Shah38ccf5b2019-07-03 10:22:11 +0530519 qdf_dp_trace_log_pkt(vdev->vdev_id, msdu, QDF_TX,
520 QDF_TRACE_DEFAULT_PDEV_ID);
521 DPTRACE(qdf_dp_trace_data_pkt(msdu, QDF_TRACE_DEFAULT_PDEV_ID,
522 QDF_DP_TRACE_TX_PACKET_RECORD,
523 tx_desc->id, QDF_TX));
524
Nirav Shah52d85aa2018-04-26 14:03:00 +0530525 if (tx_spec != OL_TX_SPEC_STD) {
526#if defined(FEATURE_WLAN_TDLS)
527 if (tx_spec & OL_TX_SPEC_NO_FREE) {
528 tx_desc->pkt_type = OL_TX_FRM_NO_FREE;
529 } else if (tx_spec & OL_TX_SPEC_TSO) {
530#else
531 if (tx_spec & OL_TX_SPEC_TSO) {
532#endif
533 tx_desc->pkt_type = OL_TX_FRM_TSO;
534 }
535 if (ol_txrx_tx_is_raw(tx_spec)) {
536 /* CHECK THIS: does this need
537 * to happen after htt_tx_desc_init?
538 */
539 /* different types of raw frames */
540 u_int8_t sub_type =
541 ol_txrx_tx_raw_subtype(
542 tx_spec);
543 htt_tx_desc_type(htt_pdev,
544 tx_desc->htt_tx_desc,
545 htt_pkt_type_raw,
546 sub_type);
547 }
548 }
549
550 tx_msdu_info.htt.info.ext_tid = qdf_nbuf_get_tid(msdu);
551 tx_msdu_info.htt.info.vdev_id = vdev->vdev_id;
552 tx_msdu_info.htt.info.frame_type = htt_frm_type_data;
553 tx_msdu_info.htt.info.l2_hdr_type = pdev->htt_pkt_type;
Nirav Shah7f37dbe2019-08-05 17:43:43 +0530554
555 if (QDF_NBUF_CB_TX_EXTRA_FRAG_FLAGS_NOTIFY_COMP(msdu)
556 == 1) {
557 tx_msdu_info.htt.action.tx_comp_req = 1;
558 tx_desc->pkt_type = OL_TX_FRM_NO_FREE;
559 } else {
560 tx_msdu_info.htt.action.tx_comp_req =
561 tx_comp_req;
562 }
Nirav Shah52d85aa2018-04-26 14:03:00 +0530563
564 /* If the vdev is in OCB mode,
565 * parse the tx control header.
566 */
567 if (vdev->opmode == wlan_op_mode_ocb) {
568 if (!parse_ocb_tx_header(msdu, &tx_ctrl)) {
569 /* There was an error parsing
570 * the header.Skip this packet.
571 */
572 goto MSDU_LOOP_BOTTOM;
573 }
574 }
575
576 txq = ol_tx_classify(vdev, tx_desc, msdu,
577 &tx_msdu_info);
578
Tiger Yuf1551cb2018-10-26 13:11:12 +0800579 /* initialize the HW tx descriptor */
580 htt_tx_desc_init(
581 pdev->htt_pdev, tx_desc->htt_tx_desc,
582 tx_desc->htt_tx_desc_paddr,
583 ol_tx_desc_id(pdev, tx_desc),
584 msdu,
585 &tx_msdu_info.htt,
586 &tx_msdu_info.tso_info,
587 &tx_ctrl,
588 vdev->opmode == wlan_op_mode_ocb);
589
Nirav Shah52d85aa2018-04-26 14:03:00 +0530590 if ((!txq) || TX_FILTER_CHECK(&tx_msdu_info)) {
591 /* drop this frame,
592 * but try sending subsequent frames
593 */
594 /* TXRX_STATS_MSDU_LIST_INCR(pdev,
595 * tx.dropped.no_txq, msdu);
596 */
597 qdf_atomic_inc(&pdev->tx_queue.rsrc_cnt);
598 ol_tx_desc_frame_free_nonstd(pdev, tx_desc, 1);
599 if (tx_msdu_info.peer) {
600 /* remove the peer reference
601 * added above
602 */
603 ol_txrx_peer_release_ref(
604 tx_msdu_info.peer,
605 PEER_DEBUG_ID_OL_INTERNAL);
606 }
607 goto MSDU_LOOP_BOTTOM;
608 }
609
610 if (tx_msdu_info.peer) {
611 /*
612 * If the state is not associated then drop all
613 * the data packets received for that peer
614 */
615 if (tx_msdu_info.peer->state ==
616 OL_TXRX_PEER_STATE_DISC) {
617 qdf_atomic_inc(
618 &pdev->tx_queue.rsrc_cnt);
619 ol_tx_desc_frame_free_nonstd(pdev,
620 tx_desc,
621 1);
622 ol_txrx_peer_release_ref(
623 tx_msdu_info.peer,
624 PEER_DEBUG_ID_OL_INTERNAL);
625 msdu = next;
626 continue;
627 } else if (tx_msdu_info.peer->state !=
628 OL_TXRX_PEER_STATE_AUTH) {
629 if (tx_msdu_info.htt.info.ethertype !=
630 ETHERTYPE_PAE &&
631 tx_msdu_info.htt.info.ethertype
632 != ETHERTYPE_WAI) {
633 qdf_atomic_inc(
634 &pdev->tx_queue.
635 rsrc_cnt);
636 ol_tx_desc_frame_free_nonstd(
637 pdev,
638 tx_desc, 1);
639 ol_txrx_peer_release_ref(
640 tx_msdu_info.peer,
641 PEER_DEBUG_ID_OL_INTERNAL);
642 msdu = next;
643 continue;
644 }
645 }
646 }
647 /*
648 * Initialize the HTT tx desc l2 header offset field.
649 * htt_tx_desc_mpdu_header needs to be called to
650 * make sure, the l2 header size is initialized
651 * correctly to handle cases where TX ENCAP is disabled
652 * or Tx Encap fails to perform Encap
653 */
654 htt_tx_desc_mpdu_header(tx_desc->htt_tx_desc, 0);
655
656 /*
657 * Note: when the driver is built without support for
658 * SW tx encap,the following macro is a no-op.
659 * When the driver is built with support for SW tx
660 * encap, it performs encap, and if an error is
661 * encountered, jumps to the MSDU_LOOP_BOTTOM label.
662 */
663 if (ol_tx_encap_wrapper(pdev, vdev, tx_desc, msdu,
664 &tx_msdu_info))
665 goto MSDU_LOOP_BOTTOM;
666
Nirav Shah52d85aa2018-04-26 14:03:00 +0530667 /*
668 * If debug display is enabled, show the meta-data
669 * being downloaded to the target via the
670 * HTT tx descriptor.
671 */
672 htt_tx_desc_display(tx_desc->htt_tx_desc);
673
674 ol_tx_enqueue(pdev, txq, tx_desc, &tx_msdu_info);
675 if (tx_msdu_info.peer) {
676 OL_TX_PEER_STATS_UPDATE(tx_msdu_info.peer,
677 msdu);
678 /* remove the peer reference added above */
679 ol_txrx_peer_release_ref
680 (tx_msdu_info.peer,
681 PEER_DEBUG_ID_OL_INTERNAL);
682 }
683MSDU_LOOP_BOTTOM:
684 msdu = next;
685 }
Tiger Yue40e7832019-04-25 10:46:53 +0800686
687 if (call_sched)
688 ol_tx_sched(pdev);
Nirav Shah52d85aa2018-04-26 14:03:00 +0530689 return NULL; /* all MSDUs were accepted */
690}
691
Tiger Yue40e7832019-04-25 10:46:53 +0800692#ifdef QCA_SUPPORT_TXRX_DRIVER_TCP_DEL_ACK
693
694/**
695 * ol_tx_pdev_reset_driver_del_ack() - reset driver delayed ack enabled flag
Rakesh Pillai6a36b0a2019-09-06 16:30:05 +0530696 * @soc_hdl: soc handle
697 * @pdev_id: datapath pdev identifier
Tiger Yue40e7832019-04-25 10:46:53 +0800698 *
699 * Return: none
700 */
701void
Rakesh Pillai6a36b0a2019-09-06 16:30:05 +0530702ol_tx_pdev_reset_driver_del_ack(struct cdp_soc_t *soc_hdl, uint8_t pdev_id)
Tiger Yue40e7832019-04-25 10:46:53 +0800703{
Rakesh Pillai6a36b0a2019-09-06 16:30:05 +0530704 struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl);
705 ol_txrx_pdev_handle pdev = ol_txrx_get_pdev_from_pdev_id(soc, pdev_id);
Tiger Yue40e7832019-04-25 10:46:53 +0800706 struct ol_txrx_vdev_t *vdev;
707
708 if (!pdev)
709 return;
710
711 TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) {
712 vdev->driver_del_ack_enabled = false;
713
714 dp_debug("vdev_id %d driver_del_ack_enabled %d",
715 vdev->vdev_id, vdev->driver_del_ack_enabled);
716 }
717}
718
719/**
720 * ol_tx_vdev_set_driver_del_ack_enable() - set driver delayed ack enabled flag
Rakesh Pillai6a36b0a2019-09-06 16:30:05 +0530721 * @soc_hdl: datapath soc handle
Tiger Yue40e7832019-04-25 10:46:53 +0800722 * @vdev_id: vdev id
723 * @rx_packets: number of rx packets
724 * @time_in_ms: time in ms
725 * @high_th: high threshold
726 * @low_th: low threshold
727 *
728 * Return: none
729 */
730void
Rakesh Pillai6a36b0a2019-09-06 16:30:05 +0530731ol_tx_vdev_set_driver_del_ack_enable(struct cdp_soc_t *soc_hdl,
732 uint8_t vdev_id,
Tiger Yue40e7832019-04-25 10:46:53 +0800733 unsigned long rx_packets,
734 uint32_t time_in_ms,
735 uint32_t high_th,
736 uint32_t low_th)
737{
738 struct ol_txrx_vdev_t *vdev =
739 (struct ol_txrx_vdev_t *)
740 ol_txrx_get_vdev_from_vdev_id(vdev_id);
741 bool old_driver_del_ack_enabled;
742
743 if ((!vdev) || (low_th > high_th))
744 return;
745
746 old_driver_del_ack_enabled = vdev->driver_del_ack_enabled;
747 if (rx_packets > high_th)
748 vdev->driver_del_ack_enabled = true;
749 else if (rx_packets < low_th)
750 vdev->driver_del_ack_enabled = false;
751
752 if (old_driver_del_ack_enabled != vdev->driver_del_ack_enabled) {
753 dp_debug("vdev_id %d driver_del_ack_enabled %d rx_packets %ld time_in_ms %d high_th %d low_th %d",
754 vdev->vdev_id, vdev->driver_del_ack_enabled,
755 rx_packets, time_in_ms, high_th, low_th);
756 }
757}
758
759/**
760 * ol_tx_hl_send_all_tcp_ack() - send all queued tcp ack packets
761 * @vdev: vdev handle
762 *
763 * Return: none
764 */
765void ol_tx_hl_send_all_tcp_ack(struct ol_txrx_vdev_t *vdev)
766{
767 int i;
768 struct tcp_stream_node *tcp_node_list;
769 struct tcp_stream_node *temp;
Li Feng1b311682019-10-18 11:08:13 +0800770 struct ol_txrx_pdev_t *pdev = vdev->pdev;
Tiger Yue40e7832019-04-25 10:46:53 +0800771
772 for (i = 0; i < OL_TX_HL_DEL_ACK_HASH_SIZE; i++) {
773 tcp_node_list = NULL;
774 qdf_spin_lock_bh(&vdev->tcp_ack_hash.node[i].hash_node_lock);
775 if (vdev->tcp_ack_hash.node[i].no_of_entries)
776 tcp_node_list = vdev->tcp_ack_hash.node[i].head;
777
778 vdev->tcp_ack_hash.node[i].no_of_entries = 0;
779 vdev->tcp_ack_hash.node[i].head = NULL;
780 qdf_spin_unlock_bh(&vdev->tcp_ack_hash.node[i].hash_node_lock);
781
782 /* Send all packets */
783 while (tcp_node_list) {
Subrat Dashc8259cd2019-09-04 16:28:19 +0530784 int tx_comp_req = pdev->cfg.default_tx_comp_req ||
785 pdev->cfg.request_tx_comp;
Tiger Yue40e7832019-04-25 10:46:53 +0800786 qdf_nbuf_t msdu_list;
787
788 temp = tcp_node_list;
789 tcp_node_list = temp->next;
790
791 msdu_list = ol_tx_hl_base(vdev, OL_TX_SPEC_STD,
792 temp->head,
793 tx_comp_req, false);
794 if (msdu_list)
795 qdf_nbuf_tx_free(msdu_list, 1/*error*/);
796 ol_txrx_vdev_free_tcp_node(vdev, temp);
797 }
798 }
799 ol_tx_sched(vdev->pdev);
800}
801
802/**
803 * tcp_del_ack_tasklet() - tasklet function to send ack packets
804 * @data: vdev handle
805 *
806 * Return: none
807 */
808void tcp_del_ack_tasklet(void *data)
809{
810 struct ol_txrx_vdev_t *vdev = data;
811
812 ol_tx_hl_send_all_tcp_ack(vdev);
813}
814
815/**
816 * ol_tx_get_stream_id() - get stream_id from packet info
817 * @info: packet info
818 *
819 * Return: stream_id
820 */
821uint16_t ol_tx_get_stream_id(struct packet_info *info)
822{
823 return ((info->dst_port + info->dst_ip + info->src_port + info->src_ip)
824 & (OL_TX_HL_DEL_ACK_HASH_SIZE - 1));
825}
826
827/**
828 * ol_tx_is_tcp_ack() - check whether the packet is tcp ack frame
829 * @msdu: packet
830 *
831 * Return: true if the packet is tcp ack frame
832 */
833static bool
834ol_tx_is_tcp_ack(qdf_nbuf_t msdu)
835{
836 uint16_t ether_type;
837 uint8_t protocol;
838 uint8_t flag, ip_header_len, tcp_header_len;
839 uint32_t seg_len;
840 uint8_t *skb_data;
841 uint32_t skb_len;
842 bool tcp_acked = false;
843 uint32_t tcp_header_off;
844
845 qdf_nbuf_peek_header(msdu, &skb_data, &skb_len);
846 if (skb_len < (QDF_NBUF_TRAC_IPV4_OFFSET +
847 QDF_NBUF_TRAC_IPV4_HEADER_SIZE +
848 QDF_NBUF_TRAC_TCP_FLAGS_OFFSET))
849 goto exit;
850
851 ether_type = (uint16_t)(*(uint16_t *)
852 (skb_data + QDF_NBUF_TRAC_ETH_TYPE_OFFSET));
853 protocol = (uint16_t)(*(uint16_t *)
854 (skb_data + QDF_NBUF_TRAC_IPV4_PROTO_TYPE_OFFSET));
855
856 if ((QDF_SWAP_U16(QDF_NBUF_TRAC_IPV4_ETH_TYPE) == ether_type) &&
857 (protocol == QDF_NBUF_TRAC_TCP_TYPE)) {
858 ip_header_len = ((uint8_t)(*(uint8_t *)
859 (skb_data + QDF_NBUF_TRAC_IPV4_OFFSET)) &
860 QDF_NBUF_TRAC_IPV4_HEADER_MASK) << 2;
861 tcp_header_off = QDF_NBUF_TRAC_IPV4_OFFSET + ip_header_len;
862
863 tcp_header_len = ((uint8_t)(*(uint8_t *)
864 (skb_data + tcp_header_off +
865 QDF_NBUF_TRAC_TCP_HEADER_LEN_OFFSET))) >> 2;
866 seg_len = skb_len - tcp_header_len - tcp_header_off;
867 flag = (uint8_t)(*(uint8_t *)
868 (skb_data + tcp_header_off +
869 QDF_NBUF_TRAC_TCP_FLAGS_OFFSET));
870
871 if ((flag == QDF_NBUF_TRAC_TCP_ACK_MASK) && (seg_len == 0))
872 tcp_acked = true;
873 }
874
875exit:
876
877 return tcp_acked;
878}
879
880/**
881 * ol_tx_get_packet_info() - update packet info for passed msdu
882 * @msdu: packet
883 * @info: packet info
884 *
885 * Return: none
886 */
887void ol_tx_get_packet_info(qdf_nbuf_t msdu, struct packet_info *info)
888{
889 uint16_t ether_type;
890 uint8_t protocol;
891 uint8_t flag, ip_header_len, tcp_header_len;
892 uint32_t seg_len;
893 uint8_t *skb_data;
894 uint32_t skb_len;
895 uint32_t tcp_header_off;
896
897 info->type = NO_TCP_PKT;
898
899 qdf_nbuf_peek_header(msdu, &skb_data, &skb_len);
900 if (skb_len < (QDF_NBUF_TRAC_IPV4_OFFSET +
901 QDF_NBUF_TRAC_IPV4_HEADER_SIZE +
902 QDF_NBUF_TRAC_TCP_FLAGS_OFFSET))
903 return;
904
905 ether_type = (uint16_t)(*(uint16_t *)
906 (skb_data + QDF_NBUF_TRAC_ETH_TYPE_OFFSET));
907 protocol = (uint16_t)(*(uint16_t *)
908 (skb_data + QDF_NBUF_TRAC_IPV4_PROTO_TYPE_OFFSET));
909
910 if ((QDF_SWAP_U16(QDF_NBUF_TRAC_IPV4_ETH_TYPE) == ether_type) &&
911 (protocol == QDF_NBUF_TRAC_TCP_TYPE)) {
912 ip_header_len = ((uint8_t)(*(uint8_t *)
913 (skb_data + QDF_NBUF_TRAC_IPV4_OFFSET)) &
914 QDF_NBUF_TRAC_IPV4_HEADER_MASK) << 2;
915 tcp_header_off = QDF_NBUF_TRAC_IPV4_OFFSET + ip_header_len;
916
917 tcp_header_len = ((uint8_t)(*(uint8_t *)
918 (skb_data + tcp_header_off +
919 QDF_NBUF_TRAC_TCP_HEADER_LEN_OFFSET))) >> 2;
920 seg_len = skb_len - tcp_header_len - tcp_header_off;
921 flag = (uint8_t)(*(uint8_t *)
922 (skb_data + tcp_header_off +
923 QDF_NBUF_TRAC_TCP_FLAGS_OFFSET));
924
925 info->src_ip = QDF_SWAP_U32((uint32_t)(*(uint32_t *)
926 (skb_data + QDF_NBUF_TRAC_IPV4_SRC_ADDR_OFFSET)));
927 info->dst_ip = QDF_SWAP_U32((uint32_t)(*(uint32_t *)
928 (skb_data + QDF_NBUF_TRAC_IPV4_DEST_ADDR_OFFSET)));
929 info->src_port = QDF_SWAP_U16((uint16_t)(*(uint16_t *)
930 (skb_data + tcp_header_off +
931 QDF_NBUF_TRAC_TCP_SPORT_OFFSET)));
932 info->dst_port = QDF_SWAP_U16((uint16_t)(*(uint16_t *)
933 (skb_data + tcp_header_off +
934 QDF_NBUF_TRAC_TCP_DPORT_OFFSET)));
935 info->stream_id = ol_tx_get_stream_id(info);
936
937 if ((flag == QDF_NBUF_TRAC_TCP_ACK_MASK) && (seg_len == 0)) {
938 info->type = TCP_PKT_ACK;
939 info->ack_number = (uint32_t)(*(uint32_t *)
940 (skb_data + tcp_header_off +
941 QDF_NBUF_TRAC_TCP_ACK_OFFSET));
942 info->ack_number = QDF_SWAP_U32(info->ack_number);
943 } else {
944 info->type = TCP_PKT_NO_ACK;
945 }
946 }
947}
948
949/**
950 * ol_tx_hl_find_and_send_tcp_stream() - find and send tcp stream for passed
951 * stream info
952 * @vdev: vdev handle
953 * @info: packet info
954 *
955 * Return: none
956 */
957void ol_tx_hl_find_and_send_tcp_stream(struct ol_txrx_vdev_t *vdev,
958 struct packet_info *info)
959{
960 uint8_t no_of_entries;
961 struct tcp_stream_node *node_to_be_remove = NULL;
Li Feng1b311682019-10-18 11:08:13 +0800962 struct ol_txrx_pdev_t *pdev = vdev->pdev;
Tiger Yue40e7832019-04-25 10:46:53 +0800963
964 /* remove tcp node from hash */
965 qdf_spin_lock_bh(&vdev->tcp_ack_hash.node[info->stream_id].
966 hash_node_lock);
967
968 no_of_entries = vdev->tcp_ack_hash.node[info->stream_id].
969 no_of_entries;
970 if (no_of_entries > 1) {
971 /* collision case */
972 struct tcp_stream_node *head =
973 vdev->tcp_ack_hash.node[info->stream_id].head;
974 struct tcp_stream_node *temp;
975
976 if ((head->dst_ip == info->dst_ip) &&
977 (head->src_ip == info->src_ip) &&
978 (head->src_port == info->src_port) &&
979 (head->dst_port == info->dst_port)) {
980 node_to_be_remove = head;
981 vdev->tcp_ack_hash.node[info->stream_id].head =
982 head->next;
983 vdev->tcp_ack_hash.node[info->stream_id].
984 no_of_entries--;
985 } else {
986 temp = head;
987 while (temp->next) {
988 if ((temp->next->dst_ip == info->dst_ip) &&
989 (temp->next->src_ip == info->src_ip) &&
990 (temp->next->src_port == info->src_port) &&
991 (temp->next->dst_port == info->dst_port)) {
992 node_to_be_remove = temp->next;
993 temp->next = temp->next->next;
994 vdev->tcp_ack_hash.
995 node[info->stream_id].
996 no_of_entries--;
997 break;
998 }
999 temp = temp->next;
1000 }
1001 }
1002 } else if (no_of_entries == 1) {
1003 /* Only one tcp_node */
1004 node_to_be_remove =
1005 vdev->tcp_ack_hash.node[info->stream_id].head;
1006 vdev->tcp_ack_hash.node[info->stream_id].head = NULL;
1007 vdev->tcp_ack_hash.node[info->stream_id].no_of_entries = 0;
1008 }
1009 qdf_spin_unlock_bh(&vdev->tcp_ack_hash.
1010 node[info->stream_id].hash_node_lock);
1011
1012 /* send packets */
1013 if (node_to_be_remove) {
Subrat Dashc8259cd2019-09-04 16:28:19 +05301014 int tx_comp_req = pdev->cfg.default_tx_comp_req ||
1015 pdev->cfg.request_tx_comp;
Tiger Yue40e7832019-04-25 10:46:53 +08001016 qdf_nbuf_t msdu_list;
1017
1018 msdu_list = ol_tx_hl_base(vdev, OL_TX_SPEC_STD,
1019 node_to_be_remove->head,
1020 tx_comp_req, true);
1021 if (msdu_list)
1022 qdf_nbuf_tx_free(msdu_list, 1/*error*/);
1023 ol_txrx_vdev_free_tcp_node(vdev, node_to_be_remove);
1024 }
1025}
1026
1027static struct tcp_stream_node *
1028ol_tx_hl_rep_tcp_ack(struct ol_txrx_vdev_t *vdev, qdf_nbuf_t msdu,
1029 struct packet_info *info, bool *is_found,
1030 bool *start_timer)
1031{
1032 struct tcp_stream_node *node_to_be_remove = NULL;
1033 struct tcp_stream_node *head =
1034 vdev->tcp_ack_hash.node[info->stream_id].head;
1035 struct tcp_stream_node *temp;
1036
1037 if ((head->dst_ip == info->dst_ip) &&
1038 (head->src_ip == info->src_ip) &&
1039 (head->src_port == info->src_port) &&
1040 (head->dst_port == info->dst_port)) {
1041 *is_found = true;
1042 if ((head->ack_number < info->ack_number) &&
1043 (head->no_of_ack_replaced <
1044 ol_cfg_get_del_ack_count_value(vdev->pdev->ctrl_pdev))) {
1045 /* replace ack packet */
1046 qdf_nbuf_tx_free(head->head, 1);
1047 head->head = msdu;
1048 head->ack_number = info->ack_number;
1049 head->no_of_ack_replaced++;
1050 *start_timer = true;
1051
1052 vdev->no_of_tcpack_replaced++;
1053
1054 if (head->no_of_ack_replaced ==
1055 ol_cfg_get_del_ack_count_value(
1056 vdev->pdev->ctrl_pdev)) {
1057 node_to_be_remove = head;
1058 vdev->tcp_ack_hash.node[info->stream_id].head =
1059 head->next;
1060 vdev->tcp_ack_hash.node[info->stream_id].
1061 no_of_entries--;
1062 }
1063 } else {
1064 /* append and send packets */
1065 head->head->next = msdu;
1066 node_to_be_remove = head;
1067 vdev->tcp_ack_hash.node[info->stream_id].head =
1068 head->next;
1069 vdev->tcp_ack_hash.node[info->stream_id].
1070 no_of_entries--;
1071 }
1072 } else {
1073 temp = head;
1074 while (temp->next) {
1075 if ((temp->next->dst_ip == info->dst_ip) &&
1076 (temp->next->src_ip == info->src_ip) &&
1077 (temp->next->src_port == info->src_port) &&
1078 (temp->next->dst_port == info->dst_port)) {
1079 *is_found = true;
1080 if ((temp->next->ack_number <
1081 info->ack_number) &&
1082 (temp->next->no_of_ack_replaced <
1083 ol_cfg_get_del_ack_count_value(
1084 vdev->pdev->ctrl_pdev))) {
1085 /* replace ack packet */
1086 qdf_nbuf_tx_free(temp->next->head, 1);
1087 temp->next->head = msdu;
1088 temp->next->ack_number =
1089 info->ack_number;
1090 temp->next->no_of_ack_replaced++;
1091 *start_timer = true;
1092
1093 vdev->no_of_tcpack_replaced++;
1094
1095 if (temp->next->no_of_ack_replaced ==
1096 ol_cfg_get_del_ack_count_value(
1097 vdev->pdev->ctrl_pdev)) {
1098 node_to_be_remove = temp->next;
1099 temp->next = temp->next->next;
1100 vdev->tcp_ack_hash.
1101 node[info->stream_id].
1102 no_of_entries--;
1103 }
1104 } else {
1105 /* append and send packets */
1106 temp->next->head->next = msdu;
1107 node_to_be_remove = temp->next;
1108 temp->next = temp->next->next;
1109 vdev->tcp_ack_hash.
1110 node[info->stream_id].
1111 no_of_entries--;
1112 }
1113 break;
1114 }
1115 temp = temp->next;
1116 }
1117 }
1118 return node_to_be_remove;
1119}
1120
1121/**
1122 * ol_tx_hl_find_and_replace_tcp_ack() - find and replace tcp ack packet for
1123 * passed packet info
1124 * @vdev: vdev handle
1125 * @msdu: packet
1126 * @info: packet info
1127 *
1128 * Return: none
1129 */
1130void ol_tx_hl_find_and_replace_tcp_ack(struct ol_txrx_vdev_t *vdev,
1131 qdf_nbuf_t msdu,
1132 struct packet_info *info)
1133{
1134 uint8_t no_of_entries;
1135 struct tcp_stream_node *node_to_be_remove = NULL;
1136 bool is_found = false, start_timer = false;
Li Feng1b311682019-10-18 11:08:13 +08001137 struct ol_txrx_pdev_t *pdev = vdev->pdev;
Tiger Yue40e7832019-04-25 10:46:53 +08001138
1139 /* replace ack if required or send packets */
1140 qdf_spin_lock_bh(&vdev->tcp_ack_hash.node[info->stream_id].
1141 hash_node_lock);
1142
1143 no_of_entries = vdev->tcp_ack_hash.node[info->stream_id].no_of_entries;
1144 if (no_of_entries > 0) {
1145 node_to_be_remove = ol_tx_hl_rep_tcp_ack(vdev, msdu, info,
1146 &is_found,
1147 &start_timer);
1148 }
1149
1150 if (no_of_entries == 0 || !is_found) {
1151 /* Alloc new tcp node */
1152 struct tcp_stream_node *new_node;
1153
1154 new_node = ol_txrx_vdev_alloc_tcp_node(vdev);
1155 if (!new_node) {
1156 qdf_spin_unlock_bh(&vdev->tcp_ack_hash.
1157 node[info->stream_id].hash_node_lock);
1158 dp_alert("Malloc failed");
1159 return;
1160 }
1161 new_node->stream_id = info->stream_id;
1162 new_node->dst_ip = info->dst_ip;
1163 new_node->src_ip = info->src_ip;
1164 new_node->dst_port = info->dst_port;
1165 new_node->src_port = info->src_port;
1166 new_node->ack_number = info->ack_number;
1167 new_node->head = msdu;
1168 new_node->next = NULL;
1169 new_node->no_of_ack_replaced = 0;
1170
1171 start_timer = true;
1172 /* insert new_node */
1173 if (!vdev->tcp_ack_hash.node[info->stream_id].head) {
1174 vdev->tcp_ack_hash.node[info->stream_id].head =
1175 new_node;
1176 vdev->tcp_ack_hash.node[info->stream_id].
1177 no_of_entries = 1;
1178 } else {
1179 struct tcp_stream_node *temp =
1180 vdev->tcp_ack_hash.node[info->stream_id].head;
1181 while (temp->next)
1182 temp = temp->next;
1183
1184 temp->next = new_node;
1185 vdev->tcp_ack_hash.node[info->stream_id].
1186 no_of_entries++;
1187 }
1188 }
1189 qdf_spin_unlock_bh(&vdev->tcp_ack_hash.node[info->stream_id].
1190 hash_node_lock);
1191
1192 /* start timer */
1193 if (start_timer &&
1194 (!qdf_atomic_read(&vdev->tcp_ack_hash.is_timer_running))) {
1195 qdf_hrtimer_start(&vdev->tcp_ack_hash.timer,
1196 qdf_ns_to_ktime((
1197 ol_cfg_get_del_ack_timer_value(
1198 vdev->pdev->ctrl_pdev) *
1199 1000000)),
1200 __QDF_HRTIMER_MODE_REL);
1201 qdf_atomic_set(&vdev->tcp_ack_hash.is_timer_running, 1);
1202 }
1203
1204 /* send packets */
1205 if (node_to_be_remove) {
Subrat Dashc8259cd2019-09-04 16:28:19 +05301206 int tx_comp_req = pdev->cfg.default_tx_comp_req ||
1207 pdev->cfg.request_tx_comp;
Tiger Yue40e7832019-04-25 10:46:53 +08001208 qdf_nbuf_t msdu_list = NULL;
1209
1210 msdu_list = ol_tx_hl_base(vdev, OL_TX_SPEC_STD,
1211 node_to_be_remove->head,
1212 tx_comp_req, true);
1213 if (msdu_list)
1214 qdf_nbuf_tx_free(msdu_list, 1/*error*/);
1215 ol_txrx_vdev_free_tcp_node(vdev, node_to_be_remove);
1216 }
1217}
1218
1219/**
1220 * ol_tx_hl_vdev_tcp_del_ack_timer() - delayed ack timer function
1221 * @timer: timer handle
1222 *
1223 * Return: enum
1224 */
1225enum qdf_hrtimer_restart_status
1226ol_tx_hl_vdev_tcp_del_ack_timer(qdf_hrtimer_data_t *timer)
1227{
1228 struct ol_txrx_vdev_t *vdev = qdf_container_of(timer,
1229 struct ol_txrx_vdev_t,
1230 tcp_ack_hash.timer);
1231 enum qdf_hrtimer_restart_status ret = __QDF_HRTIMER_NORESTART;
1232
1233 qdf_sched_bh(&vdev->tcp_ack_hash.tcp_del_ack_tq);
1234 qdf_atomic_set(&vdev->tcp_ack_hash.is_timer_running, 0);
1235 return ret;
1236}
1237
1238/**
1239 * ol_tx_hl_del_ack_queue_flush_all() - drop all queued packets
1240 * @vdev: vdev handle
1241 *
1242 * Return: none
1243 */
1244void ol_tx_hl_del_ack_queue_flush_all(struct ol_txrx_vdev_t *vdev)
1245{
1246 int i;
1247 struct tcp_stream_node *tcp_node_list;
1248 struct tcp_stream_node *temp;
1249
1250 qdf_hrtimer_cancel(&vdev->tcp_ack_hash.timer);
1251 for (i = 0; i < OL_TX_HL_DEL_ACK_HASH_SIZE; i++) {
1252 tcp_node_list = NULL;
1253 qdf_spin_lock_bh(&vdev->tcp_ack_hash.node[i].hash_node_lock);
1254
1255 if (vdev->tcp_ack_hash.node[i].no_of_entries)
1256 tcp_node_list = vdev->tcp_ack_hash.node[i].head;
1257
1258 vdev->tcp_ack_hash.node[i].no_of_entries = 0;
1259 vdev->tcp_ack_hash.node[i].head = NULL;
1260 qdf_spin_unlock_bh(&vdev->tcp_ack_hash.node[i].hash_node_lock);
1261
1262 /* free all packets */
1263 while (tcp_node_list) {
1264 temp = tcp_node_list;
1265 tcp_node_list = temp->next;
1266
1267 qdf_nbuf_tx_free(temp->head, 1/*error*/);
1268 ol_txrx_vdev_free_tcp_node(vdev, temp);
1269 }
1270 }
1271 ol_txrx_vdev_deinit_tcp_del_ack(vdev);
1272}
1273
1274/**
1275 * ol_txrx_vdev_init_tcp_del_ack() - initialize tcp delayed ack structure
1276 * @vdev: vdev handle
1277 *
1278 * Return: none
1279 */
1280void ol_txrx_vdev_init_tcp_del_ack(struct ol_txrx_vdev_t *vdev)
1281{
1282 int i;
1283
1284 vdev->driver_del_ack_enabled = false;
1285
1286 dp_debug("vdev-id=%u, driver_del_ack_enabled=%d",
1287 vdev->vdev_id,
1288 vdev->driver_del_ack_enabled);
1289
1290 vdev->no_of_tcpack = 0;
1291 vdev->no_of_tcpack_replaced = 0;
1292
1293 qdf_hrtimer_init(&vdev->tcp_ack_hash.timer,
1294 ol_tx_hl_vdev_tcp_del_ack_timer,
1295 __QDF_CLOCK_MONOTONIC,
1296 __QDF_HRTIMER_MODE_REL,
1297 QDF_CONTEXT_HARDWARE
1298 );
1299 qdf_create_bh(&vdev->tcp_ack_hash.tcp_del_ack_tq,
1300 tcp_del_ack_tasklet,
1301 vdev);
1302 qdf_atomic_init(&vdev->tcp_ack_hash.is_timer_running);
1303 qdf_atomic_init(&vdev->tcp_ack_hash.tcp_node_in_use_count);
1304 qdf_spinlock_create(&vdev->tcp_ack_hash.tcp_free_list_lock);
1305 vdev->tcp_ack_hash.tcp_free_list = NULL;
1306 for (i = 0; i < OL_TX_HL_DEL_ACK_HASH_SIZE; i++) {
1307 qdf_spinlock_create(&vdev->tcp_ack_hash.node[i].hash_node_lock);
1308 vdev->tcp_ack_hash.node[i].no_of_entries = 0;
1309 vdev->tcp_ack_hash.node[i].head = NULL;
1310 }
1311}
1312
1313/**
1314 * ol_txrx_vdev_deinit_tcp_del_ack() - deinitialize tcp delayed ack structure
1315 * @vdev: vdev handle
1316 *
1317 * Return: none
1318 */
1319void ol_txrx_vdev_deinit_tcp_del_ack(struct ol_txrx_vdev_t *vdev)
1320{
1321 struct tcp_stream_node *temp;
1322
1323 qdf_destroy_bh(&vdev->tcp_ack_hash.tcp_del_ack_tq);
1324
1325 qdf_spin_lock_bh(&vdev->tcp_ack_hash.tcp_free_list_lock);
1326 while (vdev->tcp_ack_hash.tcp_free_list) {
1327 temp = vdev->tcp_ack_hash.tcp_free_list;
1328 vdev->tcp_ack_hash.tcp_free_list = temp->next;
1329 qdf_mem_free(temp);
1330 }
1331 qdf_spin_unlock_bh(&vdev->tcp_ack_hash.tcp_free_list_lock);
1332}
1333
1334/**
1335 * ol_txrx_vdev_free_tcp_node() - add tcp node in free list
1336 * @vdev: vdev handle
1337 * @node: tcp stream node
1338 *
1339 * Return: none
1340 */
1341void ol_txrx_vdev_free_tcp_node(struct ol_txrx_vdev_t *vdev,
1342 struct tcp_stream_node *node)
1343{
1344 qdf_atomic_dec(&vdev->tcp_ack_hash.tcp_node_in_use_count);
1345
1346 qdf_spin_lock_bh(&vdev->tcp_ack_hash.tcp_free_list_lock);
1347 if (vdev->tcp_ack_hash.tcp_free_list) {
1348 node->next = vdev->tcp_ack_hash.tcp_free_list;
1349 vdev->tcp_ack_hash.tcp_free_list = node;
1350 } else {
1351 vdev->tcp_ack_hash.tcp_free_list = node;
1352 node->next = NULL;
1353 }
1354 qdf_spin_unlock_bh(&vdev->tcp_ack_hash.tcp_free_list_lock);
1355}
1356
1357/**
1358 * ol_txrx_vdev_alloc_tcp_node() - allocate tcp node
1359 * @vdev: vdev handle
1360 *
1361 * Return: tcp stream node
1362 */
1363struct tcp_stream_node *ol_txrx_vdev_alloc_tcp_node(struct ol_txrx_vdev_t *vdev)
1364{
1365 struct tcp_stream_node *node = NULL;
1366
1367 qdf_spin_lock_bh(&vdev->tcp_ack_hash.tcp_free_list_lock);
1368 if (vdev->tcp_ack_hash.tcp_free_list) {
1369 node = vdev->tcp_ack_hash.tcp_free_list;
1370 vdev->tcp_ack_hash.tcp_free_list = node->next;
1371 }
1372 qdf_spin_unlock_bh(&vdev->tcp_ack_hash.tcp_free_list_lock);
1373
1374 if (!node) {
1375 node = qdf_mem_malloc(sizeof(struct ol_txrx_vdev_t));
1376 if (!node)
1377 return NULL;
1378 }
1379 qdf_atomic_inc(&vdev->tcp_ack_hash.tcp_node_in_use_count);
1380 return node;
1381}
1382
1383qdf_nbuf_t
1384ol_tx_hl(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list)
1385{
1386 struct ol_txrx_pdev_t *pdev = vdev->pdev;
Subrat Dashc8259cd2019-09-04 16:28:19 +05301387 int tx_comp_req = pdev->cfg.default_tx_comp_req ||
1388 pdev->cfg.request_tx_comp;
Tiger Yue40e7832019-04-25 10:46:53 +08001389 struct packet_info pkt_info;
1390 qdf_nbuf_t temp;
1391
1392 if (ol_tx_is_tcp_ack(msdu_list))
1393 vdev->no_of_tcpack++;
1394
1395 /* check Enable through ini */
1396 if (!ol_cfg_get_del_ack_enable_value(vdev->pdev->ctrl_pdev) ||
1397 (!vdev->driver_del_ack_enabled)) {
1398 if (qdf_atomic_read(&vdev->tcp_ack_hash.tcp_node_in_use_count))
1399 ol_tx_hl_send_all_tcp_ack(vdev);
1400
1401 return ol_tx_hl_base(vdev, OL_TX_SPEC_STD, msdu_list,
1402 tx_comp_req, true);
1403 }
1404
1405 ol_tx_get_packet_info(msdu_list, &pkt_info);
1406
1407 if (pkt_info.type == TCP_PKT_NO_ACK) {
1408 ol_tx_hl_find_and_send_tcp_stream(vdev, &pkt_info);
1409 temp = ol_tx_hl_base(vdev, OL_TX_SPEC_STD, msdu_list,
1410 tx_comp_req, true);
1411 return temp;
1412 }
1413
1414 if (pkt_info.type == TCP_PKT_ACK) {
1415 ol_tx_hl_find_and_replace_tcp_ack(vdev, msdu_list, &pkt_info);
1416 return NULL;
1417 }
1418
1419 temp = ol_tx_hl_base(vdev, OL_TX_SPEC_STD, msdu_list,
1420 tx_comp_req, true);
1421 return temp;
1422}
1423#else
1424
Nirav Shahfb9b1df2019-11-15 11:40:52 +05301425#ifdef WLAN_SUPPORT_TXRX_HL_BUNDLE
1426void
1427ol_tx_pdev_reset_bundle_require(struct cdp_soc_t *soc_hdl, uint8_t pdev_id)
1428{
1429 struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl);
1430 struct ol_txrx_pdev_t *pdev = ol_txrx_get_pdev_from_pdev_id(soc,
1431 pdev_id);
1432 struct ol_txrx_vdev_t *vdev;
1433
1434 TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) {
1435 vdev->bundling_required = false;
1436 ol_txrx_info("vdev_id %d bundle_require %d\n",
1437 vdev->vdev_id, vdev->bundling_required);
1438 }
1439}
1440
1441void
1442ol_tx_vdev_set_bundle_require(uint8_t vdev_id, unsigned long tx_bytes,
1443 uint32_t time_in_ms, uint32_t high_th,
1444 uint32_t low_th)
1445{
1446 struct ol_txrx_vdev_t *vdev = (struct ol_txrx_vdev_t *)
1447 ol_txrx_get_vdev_from_vdev_id(vdev_id);
1448 bool old_bundle_required;
1449
1450 if ((!vdev) || (low_th > high_th))
1451 return;
1452
1453 old_bundle_required = vdev->bundling_required;
1454 if (tx_bytes > ((high_th * time_in_ms * 1500) / 1000))
1455 vdev->bundling_required = true;
1456 else if (tx_bytes < ((low_th * time_in_ms * 1500) / 1000))
1457 vdev->bundling_required = false;
1458
1459 if (old_bundle_required != vdev->bundling_required)
1460 ol_txrx_info("vdev_id %d bundle_require %d tx_bytes %ld time_in_ms %d high_th %d low_th %d\n",
1461 vdev->vdev_id, vdev->bundling_required, tx_bytes,
1462 time_in_ms, high_th, low_th);
1463}
1464
1465/**
1466 * ol_tx_hl_queue_flush_all() - drop all packets in vdev bundle queue
1467 * @vdev: vdev handle
1468 *
1469 * Return: none
1470 */
1471void
1472ol_tx_hl_queue_flush_all(struct ol_txrx_vdev_t *vdev)
1473{
1474 qdf_spin_lock_bh(&vdev->bundle_queue.mutex);
1475 if (vdev->bundle_queue.txq.depth != 0) {
1476 qdf_timer_stop(&vdev->bundle_queue.timer);
1477 vdev->pdev->total_bundle_queue_length -=
1478 vdev->bundle_queue.txq.depth;
1479 qdf_nbuf_tx_free(vdev->bundle_queue.txq.head, 1/*error*/);
1480 vdev->bundle_queue.txq.depth = 0;
1481 vdev->bundle_queue.txq.head = NULL;
1482 vdev->bundle_queue.txq.tail = NULL;
1483 }
1484 qdf_spin_unlock_bh(&vdev->bundle_queue.mutex);
1485}
1486
1487/**
1488 * ol_tx_hl_vdev_queue_append() - append pkt in tx queue
1489 * @vdev: vdev handle
1490 * @msdu_list: msdu list
1491 *
1492 * Return: none
1493 */
1494static void
1495ol_tx_hl_vdev_queue_append(struct ol_txrx_vdev_t *vdev, qdf_nbuf_t msdu_list)
1496{
1497 qdf_spin_lock_bh(&vdev->bundle_queue.mutex);
1498
1499 if (!vdev->bundle_queue.txq.head) {
1500 qdf_timer_start(
1501 &vdev->bundle_queue.timer,
1502 ol_cfg_get_bundle_timer_value(vdev->pdev->ctrl_pdev));
1503 vdev->bundle_queue.txq.head = msdu_list;
1504 vdev->bundle_queue.txq.tail = msdu_list;
1505 } else {
1506 qdf_nbuf_set_next(vdev->bundle_queue.txq.tail, msdu_list);
1507 }
1508
1509 while (qdf_nbuf_next(msdu_list)) {
1510 vdev->bundle_queue.txq.depth++;
1511 vdev->pdev->total_bundle_queue_length++;
1512 msdu_list = qdf_nbuf_next(msdu_list);
1513 }
1514
1515 vdev->bundle_queue.txq.depth++;
1516 vdev->pdev->total_bundle_queue_length++;
1517 vdev->bundle_queue.txq.tail = msdu_list;
1518 qdf_spin_unlock_bh(&vdev->bundle_queue.mutex);
1519}
1520
1521/**
1522 * ol_tx_hl_vdev_queue_send_all() - send all packets in vdev bundle queue
1523 * @vdev: vdev handle
1524 * @call_sched: invoke scheduler
1525 *
1526 * Return: NULL for success
1527 */
1528static qdf_nbuf_t
1529ol_tx_hl_vdev_queue_send_all(struct ol_txrx_vdev_t *vdev, bool call_sched,
1530 bool in_timer_context)
1531{
1532 qdf_nbuf_t msdu_list = NULL;
1533 qdf_nbuf_t skb_list_head, skb_list_tail;
1534 struct ol_txrx_pdev_t *pdev = vdev->pdev;
1535 int tx_comp_req = pdev->cfg.default_tx_comp_req ||
1536 pdev->cfg.request_tx_comp;
1537 int pkt_to_sent;
1538
1539 qdf_spin_lock_bh(&vdev->bundle_queue.mutex);
1540
1541 if (!vdev->bundle_queue.txq.depth) {
1542 qdf_spin_unlock_bh(&vdev->bundle_queue.mutex);
1543 return msdu_list;
1544 }
1545
1546 if (likely((qdf_atomic_read(&vdev->tx_desc_count) +
1547 vdev->bundle_queue.txq.depth) <
1548 vdev->queue_stop_th)) {
1549 qdf_timer_stop(&vdev->bundle_queue.timer);
1550 vdev->pdev->total_bundle_queue_length -=
1551 vdev->bundle_queue.txq.depth;
1552 msdu_list = ol_tx_hl_base(vdev, OL_TX_SPEC_STD,
1553 vdev->bundle_queue.txq.head,
1554 tx_comp_req, call_sched);
1555 vdev->bundle_queue.txq.depth = 0;
1556 vdev->bundle_queue.txq.head = NULL;
1557 vdev->bundle_queue.txq.tail = NULL;
1558 } else {
1559 pkt_to_sent = vdev->queue_stop_th -
1560 qdf_atomic_read(&vdev->tx_desc_count);
1561
1562 if (pkt_to_sent) {
1563 skb_list_head = vdev->bundle_queue.txq.head;
1564
1565 while (pkt_to_sent) {
1566 skb_list_tail =
1567 vdev->bundle_queue.txq.head;
1568 vdev->bundle_queue.txq.head =
1569 qdf_nbuf_next(vdev->bundle_queue.txq.head);
1570 vdev->pdev->total_bundle_queue_length--;
1571 vdev->bundle_queue.txq.depth--;
1572 pkt_to_sent--;
1573 if (!vdev->bundle_queue.txq.head) {
1574 qdf_timer_stop(
1575 &vdev->bundle_queue.timer);
1576 break;
1577 }
1578 }
1579
1580 qdf_nbuf_set_next(skb_list_tail, NULL);
1581 msdu_list = ol_tx_hl_base(vdev, OL_TX_SPEC_STD,
1582 skb_list_head, tx_comp_req,
1583 call_sched);
1584 }
1585
1586 if (in_timer_context && vdev->bundle_queue.txq.head) {
1587 qdf_timer_start(
1588 &vdev->bundle_queue.timer,
1589 ol_cfg_get_bundle_timer_value(
1590 vdev->pdev->ctrl_pdev));
1591 }
1592 }
1593 qdf_spin_unlock_bh(&vdev->bundle_queue.mutex);
1594
1595 return msdu_list;
1596}
1597
1598/**
1599 * ol_tx_hl_pdev_queue_send_all() - send all packets from all vdev bundle queue
1600 * @pdev: pdev handle
1601 *
1602 * Return: NULL for success
1603 */
1604qdf_nbuf_t
1605ol_tx_hl_pdev_queue_send_all(struct ol_txrx_pdev_t *pdev)
1606{
1607 struct ol_txrx_vdev_t *vdev;
1608 qdf_nbuf_t msdu_list;
1609
1610 TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) {
1611 msdu_list = ol_tx_hl_vdev_queue_send_all(vdev, false, false);
1612 if (msdu_list)
1613 qdf_nbuf_tx_free(msdu_list, 1/*error*/);
1614 }
1615 ol_tx_sched(pdev);
1616 return NULL; /* all msdus were accepted */
1617}
1618
1619/**
1620 * ol_tx_hl_vdev_bundle_timer() - bundle timer function
1621 * @vdev: vdev handle
1622 *
1623 * Return: none
1624 */
1625#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
1626void
1627ol_tx_hl_vdev_bundle_timer(struct timer_list *t)
1628{
1629 qdf_nbuf_t msdu_list;
1630 struct ol_txrx_vdev_t *vdev = from_timer(vdev, t, bundle_queue.timer);
1631
1632 vdev->no_of_bundle_sent_in_timer++;
1633 msdu_list = ol_tx_hl_vdev_queue_send_all(vdev, true, true);
1634 if (msdu_list)
1635 qdf_nbuf_tx_free(msdu_list, 1/*error*/);
1636}
1637#else
1638void
1639ol_tx_hl_vdev_bundle_timer(void *ctx)
1640{
1641 qdf_nbuf_t msdu_list;
1642 struct ol_txrx_vdev_t *vdev = (struct ol_txrx_vdev_t *)ctx;
1643
1644 vdev->no_of_bundle_sent_in_timer++;
1645 msdu_list = ol_tx_hl_vdev_queue_send_all(vdev, true, true);
1646 if (msdu_list)
1647 qdf_nbuf_tx_free(msdu_list, 1/*error*/);
1648}
1649#endif
1650
1651qdf_nbuf_t
1652ol_tx_hl(struct ol_txrx_vdev_t *vdev, qdf_nbuf_t msdu_list)
1653{
1654 struct ol_txrx_pdev_t *pdev = vdev->pdev;
1655 int tx_comp_req = pdev->cfg.default_tx_comp_req ||
1656 pdev->cfg.request_tx_comp;
1657
1658 /* No queuing for high priority packets */
1659 if (ol_tx_desc_is_high_prio(msdu_list)) {
1660 vdev->no_of_pkt_not_added_in_queue++;
1661 return ol_tx_hl_base(vdev, OL_TX_SPEC_STD, msdu_list,
1662 tx_comp_req, true);
1663 } else if (vdev->bundling_required &&
1664 (ol_cfg_get_bundle_size(vdev->pdev->ctrl_pdev) > 1)) {
1665 ol_tx_hl_vdev_queue_append(vdev, msdu_list);
1666
1667 if (pdev->total_bundle_queue_length >=
1668 ol_cfg_get_bundle_size(vdev->pdev->ctrl_pdev)) {
1669 vdev->no_of_bundle_sent_after_threshold++;
1670 return ol_tx_hl_pdev_queue_send_all(pdev);
1671 }
1672 } else {
1673 if (vdev->bundle_queue.txq.depth != 0) {
1674 ol_tx_hl_vdev_queue_append(vdev, msdu_list);
1675 return ol_tx_hl_vdev_queue_send_all(vdev, true, false);
1676 } else {
1677 vdev->no_of_pkt_not_added_in_queue++;
1678 return ol_tx_hl_base(vdev, OL_TX_SPEC_STD, msdu_list,
1679 tx_comp_req, true);
1680 }
1681 }
1682
1683 return NULL; /* all msdus were accepted */
1684}
1685
1686#else
1687
Nirav Shah52d85aa2018-04-26 14:03:00 +05301688qdf_nbuf_t
1689ol_tx_hl(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list)
1690{
1691 struct ol_txrx_pdev_t *pdev = vdev->pdev;
1692 int tx_comp_req = pdev->cfg.default_tx_comp_req ||
1693 pdev->cfg.request_tx_comp;
1694
Tiger Yue40e7832019-04-25 10:46:53 +08001695 return ol_tx_hl_base(vdev, OL_TX_SPEC_STD,
1696 msdu_list, tx_comp_req, true);
Nirav Shah52d85aa2018-04-26 14:03:00 +05301697}
Tiger Yue40e7832019-04-25 10:46:53 +08001698#endif
Nirav Shahfb9b1df2019-11-15 11:40:52 +05301699#endif
Nirav Shah52d85aa2018-04-26 14:03:00 +05301700
1701qdf_nbuf_t ol_tx_non_std_hl(struct ol_txrx_vdev_t *vdev,
1702 enum ol_tx_spec tx_spec,
1703 qdf_nbuf_t msdu_list)
1704{
1705 struct ol_txrx_pdev_t *pdev = vdev->pdev;
1706 int tx_comp_req = pdev->cfg.default_tx_comp_req ||
1707 pdev->cfg.request_tx_comp;
1708
1709 if (!tx_comp_req) {
1710 if ((tx_spec == OL_TX_SPEC_NO_FREE) &&
1711 (pdev->tx_data_callback.func))
1712 tx_comp_req = 1;
1713 }
Tiger Yue40e7832019-04-25 10:46:53 +08001714 return ol_tx_hl_base(vdev, tx_spec, msdu_list, tx_comp_req, true);
Nirav Shah52d85aa2018-04-26 14:03:00 +05301715}
1716
1717#ifdef FEATURE_WLAN_TDLS
1718/**
1719 * ol_txrx_copy_mac_addr_raw() - copy raw mac addr
1720 * @vdev: the data virtual device
1721 * @bss_addr: bss address
1722 *
1723 * Return: None
1724 */
1725void ol_txrx_copy_mac_addr_raw(struct cdp_vdev *pvdev, uint8_t *bss_addr)
1726{
1727 struct ol_txrx_vdev_t *vdev = (struct ol_txrx_vdev_t *)pvdev;
1728
1729 qdf_spin_lock_bh(&vdev->pdev->last_real_peer_mutex);
1730 if (bss_addr && vdev->last_real_peer &&
1731 !qdf_mem_cmp((u8 *)bss_addr,
1732 vdev->last_real_peer->mac_addr.raw,
Srinivas Girigowdaa47b45f2019-02-27 12:29:02 -08001733 QDF_MAC_ADDR_SIZE))
Nirav Shah52d85aa2018-04-26 14:03:00 +05301734 qdf_mem_copy(vdev->hl_tdls_ap_mac_addr.raw,
1735 vdev->last_real_peer->mac_addr.raw,
Srinivas Girigowdaa47b45f2019-02-27 12:29:02 -08001736 QDF_MAC_ADDR_SIZE);
Nirav Shah52d85aa2018-04-26 14:03:00 +05301737 qdf_spin_unlock_bh(&vdev->pdev->last_real_peer_mutex);
1738}
1739
1740/**
1741 * ol_txrx_add_last_real_peer() - add last peer
1742 * @pdev: the data physical device
1743 * @vdev: virtual device
1744 * @peer_id: peer id
1745 *
1746 * Return: None
1747 */
1748void
1749ol_txrx_add_last_real_peer(struct cdp_pdev *ppdev,
1750 struct cdp_vdev *pvdev, uint8_t *peer_id)
1751{
1752 struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)ppdev;
1753 struct ol_txrx_vdev_t *vdev = (struct ol_txrx_vdev_t *)pvdev;
1754 ol_txrx_peer_handle peer;
1755
1756 peer = ol_txrx_find_peer_by_addr(
1757 (struct cdp_pdev *)pdev,
1758 vdev->hl_tdls_ap_mac_addr.raw,
1759 peer_id);
1760
1761 qdf_spin_lock_bh(&pdev->last_real_peer_mutex);
1762 if (!vdev->last_real_peer && peer &&
nakul kachhwahae3e92ae2019-10-24 17:59:48 +05301763 (peer->peer_ids[0] != HTT_INVALID_PEER_ID)) {
Nirav Shah52d85aa2018-04-26 14:03:00 +05301764 vdev->last_real_peer = peer;
nakul kachhwahae3e92ae2019-10-24 17:59:48 +05301765 qdf_mem_zero(vdev->hl_tdls_ap_mac_addr.raw,
1766 QDF_MAC_ADDR_SIZE);
1767 }
Nirav Shah52d85aa2018-04-26 14:03:00 +05301768 qdf_spin_unlock_bh(&pdev->last_real_peer_mutex);
1769}
1770
1771/**
1772 * is_vdev_restore_last_peer() - check for vdev last peer
1773 * @peer: peer object
1774 *
1775 * Return: true if last peer is not null
1776 */
1777bool is_vdev_restore_last_peer(void *ppeer)
1778{
1779 struct ol_txrx_peer_t *peer = ppeer;
1780 struct ol_txrx_vdev_t *vdev;
1781
1782 vdev = peer->vdev;
1783 return vdev->last_real_peer && (vdev->last_real_peer == peer);
1784}
1785
1786/**
1787 * ol_txrx_update_last_real_peer() - check for vdev last peer
1788 * @pdev: the data physical device
1789 * @peer: peer device
1790 * @peer_id: peer id
1791 * @restore_last_peer: restore last peer flag
1792 *
1793 * Return: None
1794 */
Rachit Kankane87b16542019-02-28 14:14:36 +05301795void ol_txrx_update_last_real_peer(struct cdp_pdev *ppdev, void *pvdev,
Nirav Shah52d85aa2018-04-26 14:03:00 +05301796 uint8_t *peer_id, bool restore_last_peer)
1797{
1798 struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)ppdev;
Rachit Kankane87b16542019-02-28 14:14:36 +05301799 struct ol_txrx_vdev_t *vdev = (struct ol_txrx_vdev_t *)pvdev;
1800 struct ol_txrx_peer_t *peer;
Nirav Shah52d85aa2018-04-26 14:03:00 +05301801
1802 if (!restore_last_peer)
1803 return;
1804
Nirav Shah52d85aa2018-04-26 14:03:00 +05301805 peer = ol_txrx_find_peer_by_addr((struct cdp_pdev *)pdev,
1806 vdev->hl_tdls_ap_mac_addr.raw,
1807 peer_id);
1808
1809 qdf_spin_lock_bh(&pdev->last_real_peer_mutex);
1810 if (!vdev->last_real_peer && peer &&
nakul kachhwahae3e92ae2019-10-24 17:59:48 +05301811 (peer->peer_ids[0] != HTT_INVALID_PEER_ID)) {
Nirav Shah52d85aa2018-04-26 14:03:00 +05301812 vdev->last_real_peer = peer;
nakul kachhwahae3e92ae2019-10-24 17:59:48 +05301813 qdf_mem_zero(vdev->hl_tdls_ap_mac_addr.raw,
1814 QDF_MAC_ADDR_SIZE);
1815 }
Nirav Shah52d85aa2018-04-26 14:03:00 +05301816 qdf_spin_unlock_bh(&pdev->last_real_peer_mutex);
1817}
nakul kachhwahae3e92ae2019-10-24 17:59:48 +05301818
1819/**
1820 * ol_txrx_set_peer_as_tdls_peer() - mark peer as tdls peer
1821 * @ppeer: cdp peer
1822 * @value: false/true
1823 *
1824 * Return: None
1825 */
1826void ol_txrx_set_peer_as_tdls_peer(void *ppeer, bool val)
1827{
1828 ol_txrx_peer_handle peer = ppeer;
1829
1830 ol_txrx_info_high("peer %pK, peer->ref_cnt %d",
1831 peer, qdf_atomic_read(&peer->ref_cnt));
1832
1833 /* Mark peer as tdls */
1834 peer->is_tdls_peer = val;
1835}
1836
1837/**
1838 * ol_txrx_set_tdls_offchan_enabled() - set tdls offchan enabled
1839 * @ppeer: cdp peer
1840 * @value: false/true
1841 *
1842 * Return: None
1843 */
1844void ol_txrx_set_tdls_offchan_enabled(void *ppeer, bool val)
1845{
1846 ol_txrx_peer_handle peer = ppeer;
1847
1848 ol_txrx_info_high("peer %pK, peer->ref_cnt %d",
1849 peer, qdf_atomic_read(&peer->ref_cnt));
1850
1851 /* Set TDLS Offchan operation enable/disable */
1852 if (peer->is_tdls_peer)
1853 peer->tdls_offchan_enabled = val;
1854}
Nirav Shah52d85aa2018-04-26 14:03:00 +05301855#endif
1856
1857#if defined(CONFIG_HL_SUPPORT) && defined(DEBUG_HL_LOGGING)
1858/**
1859 * ol_txrx_pdev_txq_log_init() - initialise pdev txq logs
1860 * @pdev: the physical device object
1861 *
1862 * Return: None
1863 */
1864void ol_txrx_pdev_txq_log_init(struct ol_txrx_pdev_t *pdev)
1865{
1866 qdf_spinlock_create(&pdev->txq_log_spinlock);
1867 pdev->txq_log.size = OL_TXQ_LOG_SIZE;
1868 pdev->txq_log.oldest_record_offset = 0;
1869 pdev->txq_log.offset = 0;
1870 pdev->txq_log.allow_wrap = 1;
1871 pdev->txq_log.wrapped = 0;
1872}
1873
1874/**
1875 * ol_txrx_pdev_txq_log_destroy() - remove txq log spinlock for pdev
1876 * @pdev: the physical device object
1877 *
1878 * Return: None
1879 */
1880void ol_txrx_pdev_txq_log_destroy(struct ol_txrx_pdev_t *pdev)
1881{
1882 qdf_spinlock_destroy(&pdev->txq_log_spinlock);
1883}
1884#endif
1885
1886#if defined(DEBUG_HL_LOGGING)
1887
1888/**
1889 * ol_txrx_pdev_grp_stats_init() - initialise group stat spinlock for pdev
1890 * @pdev: the physical device object
1891 *
1892 * Return: None
1893 */
1894void ol_txrx_pdev_grp_stats_init(struct ol_txrx_pdev_t *pdev)
1895{
1896 qdf_spinlock_create(&pdev->grp_stat_spinlock);
1897 pdev->grp_stats.last_valid_index = -1;
1898 pdev->grp_stats.wrap_around = 0;
1899}
1900
1901/**
1902 * ol_txrx_pdev_grp_stat_destroy() - destroy group stat spinlock for pdev
1903 * @pdev: the physical device object
1904 *
1905 * Return: None
1906 */
1907void ol_txrx_pdev_grp_stat_destroy(struct ol_txrx_pdev_t *pdev)
1908{
1909 qdf_spinlock_destroy(&pdev->grp_stat_spinlock);
1910}
1911#endif
1912
1913#if defined(CONFIG_HL_SUPPORT) && defined(FEATURE_WLAN_TDLS)
1914
1915/**
1916 * ol_txrx_hl_tdls_flag_reset() - reset tdls flag for vdev
Rakesh Pillai6a36b0a2019-09-06 16:30:05 +05301917 * @soc_hdl: Datapath soc handle
1918 * @vdev_id: id of vdev
Nirav Shah52d85aa2018-04-26 14:03:00 +05301919 * @flag: flag
1920 *
1921 * Return: None
1922 */
1923void
Rakesh Pillai6a36b0a2019-09-06 16:30:05 +05301924ol_txrx_hl_tdls_flag_reset(struct cdp_soc_t *soc_hdl, uint8_t vdev_id,
1925 bool flag)
Nirav Shah52d85aa2018-04-26 14:03:00 +05301926{
Rakesh Pillai6a36b0a2019-09-06 16:30:05 +05301927 struct ol_txrx_vdev_t *vdev =
1928 (struct ol_txrx_vdev_t *)ol_txrx_get_vdev_from_vdev_id(vdev_id);
Nirav Shah52d85aa2018-04-26 14:03:00 +05301929
1930 vdev->hlTdlsFlag = flag;
1931}
1932#endif
1933
1934/**
1935 * ol_txrx_vdev_txqs_init() - initialise vdev tx queues
1936 * @vdev: the virtual device object
1937 *
1938 * Return: None
1939 */
1940void ol_txrx_vdev_txqs_init(struct ol_txrx_vdev_t *vdev)
1941{
1942 uint8_t i;
1943
1944 for (i = 0; i < OL_TX_VDEV_NUM_QUEUES; i++) {
1945 TAILQ_INIT(&vdev->txqs[i].head);
1946 vdev->txqs[i].paused_count.total = 0;
1947 vdev->txqs[i].frms = 0;
1948 vdev->txqs[i].bytes = 0;
1949 vdev->txqs[i].ext_tid = OL_TX_NUM_TIDS + i;
1950 vdev->txqs[i].flag = ol_tx_queue_empty;
1951 /* aggregation is not applicable for vdev tx queues */
1952 vdev->txqs[i].aggr_state = ol_tx_aggr_disabled;
1953 ol_tx_txq_set_group_ptr(&vdev->txqs[i], NULL);
1954 ol_txrx_set_txq_peer(&vdev->txqs[i], NULL);
1955 }
1956}
1957
1958/**
1959 * ol_txrx_vdev_tx_queue_free() - free vdev tx queues
1960 * @vdev: the virtual device object
1961 *
1962 * Return: None
1963 */
1964void ol_txrx_vdev_tx_queue_free(struct ol_txrx_vdev_t *vdev)
1965{
1966 struct ol_txrx_pdev_t *pdev = vdev->pdev;
1967 struct ol_tx_frms_queue_t *txq;
1968 int i;
1969
1970 for (i = 0; i < OL_TX_VDEV_NUM_QUEUES; i++) {
1971 txq = &vdev->txqs[i];
1972 ol_tx_queue_free(pdev, txq, (i + OL_TX_NUM_TIDS), false);
1973 }
1974}
1975
1976/**
1977 * ol_txrx_peer_txqs_init() - initialise peer tx queues
1978 * @pdev: the physical device object
1979 * @peer: peer object
1980 *
1981 * Return: None
1982 */
1983void ol_txrx_peer_txqs_init(struct ol_txrx_pdev_t *pdev,
1984 struct ol_txrx_peer_t *peer)
1985{
1986 uint8_t i;
1987 struct ol_txrx_vdev_t *vdev = peer->vdev;
1988
1989 qdf_spin_lock_bh(&pdev->tx_queue_spinlock);
1990 for (i = 0; i < OL_TX_NUM_TIDS; i++) {
1991 TAILQ_INIT(&peer->txqs[i].head);
1992 peer->txqs[i].paused_count.total = 0;
1993 peer->txqs[i].frms = 0;
1994 peer->txqs[i].bytes = 0;
1995 peer->txqs[i].ext_tid = i;
1996 peer->txqs[i].flag = ol_tx_queue_empty;
1997 peer->txqs[i].aggr_state = ol_tx_aggr_untried;
1998 ol_tx_set_peer_group_ptr(pdev, peer, vdev->vdev_id, i);
1999 ol_txrx_set_txq_peer(&peer->txqs[i], peer);
2000 }
2001 qdf_spin_unlock_bh(&pdev->tx_queue_spinlock);
2002
2003 /* aggregation is not applicable for mgmt and non-QoS tx queues */
2004 for (i = OL_TX_NUM_QOS_TIDS; i < OL_TX_NUM_TIDS; i++)
2005 peer->txqs[i].aggr_state = ol_tx_aggr_disabled;
2006
2007 ol_txrx_peer_pause(peer);
2008}
2009
2010/**
2011 * ol_txrx_peer_tx_queue_free() - free peer tx queues
2012 * @pdev: the physical device object
2013 * @peer: peer object
2014 *
2015 * Return: None
2016 */
2017void ol_txrx_peer_tx_queue_free(struct ol_txrx_pdev_t *pdev,
2018 struct ol_txrx_peer_t *peer)
2019{
2020 struct ol_tx_frms_queue_t *txq;
2021 uint8_t i;
2022
2023 for (i = 0; i < OL_TX_NUM_TIDS; i++) {
2024 txq = &peer->txqs[i];
2025 ol_tx_queue_free(pdev, txq, i, true);
2026 }
2027}
2028
2029#ifdef FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL
2030
2031/**
2032 * ol_txrx_update_group_credit() - update group credit for tx queue
2033 * @group: for which credit needs to be updated
2034 * @credit: credits
2035 * @absolute: TXQ group absolute
2036 *
2037 * Return: allocated pool size
2038 */
2039void ol_txrx_update_group_credit(
2040 struct ol_tx_queue_group_t *group,
2041 int32_t credit,
2042 u_int8_t absolute)
2043{
2044 if (absolute)
2045 qdf_atomic_set(&group->credit, credit);
2046 else
2047 qdf_atomic_add(credit, &group->credit);
2048}
2049
2050/**
2051 * ol_txrx_update_tx_queue_groups() - update vdev tx queue group if
2052 * vdev id mask and ac mask is not matching
2053 * @pdev: the data physical device
2054 * @group_id: TXQ group id
2055 * @credit: TXQ group credit count
2056 * @absolute: TXQ group absolute
2057 * @vdev_id_mask: TXQ vdev group id mask
2058 * @ac_mask: TQX access category mask
2059 *
2060 * Return: None
2061 */
2062void ol_txrx_update_tx_queue_groups(
2063 ol_txrx_pdev_handle pdev,
2064 u_int8_t group_id,
2065 int32_t credit,
2066 u_int8_t absolute,
2067 u_int32_t vdev_id_mask,
2068 u_int32_t ac_mask
2069 )
2070{
2071 struct ol_tx_queue_group_t *group;
2072 u_int32_t group_vdev_bit_mask, vdev_bit_mask, group_vdev_id_mask;
2073 u_int32_t membership;
2074 struct ol_txrx_vdev_t *vdev;
2075
2076 if (group_id >= OL_TX_MAX_TXQ_GROUPS) {
Nirav Shah7c8c1712018-09-10 16:01:31 +05302077 ol_txrx_warn("invalid group_id=%u, ignore update", group_id);
Nirav Shah52d85aa2018-04-26 14:03:00 +05302078 return;
2079 }
2080
2081 group = &pdev->txq_grps[group_id];
2082
2083 membership = OL_TXQ_GROUP_MEMBERSHIP_GET(vdev_id_mask, ac_mask);
2084
2085 qdf_spin_lock_bh(&pdev->tx_queue_spinlock);
2086 /*
2087 * if the membership (vdev id mask and ac mask)
2088 * matches then no need to update tx qeue groups.
2089 */
2090 if (group->membership == membership)
2091 /* Update Credit Only */
2092 goto credit_update;
2093
2094 credit += ol_txrx_distribute_group_credits(pdev, group_id,
2095 vdev_id_mask);
2096 /*
2097 * membership (vdev id mask and ac mask) is not matching
2098 * TODO: ignoring ac mask for now
2099 */
2100 qdf_assert(ac_mask == 0xffff);
2101 group_vdev_id_mask =
2102 OL_TXQ_GROUP_VDEV_ID_MASK_GET(group->membership);
2103
2104 TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) {
2105 group_vdev_bit_mask =
2106 OL_TXQ_GROUP_VDEV_ID_BIT_MASK_GET(
2107 group_vdev_id_mask, vdev->vdev_id);
2108 vdev_bit_mask =
2109 OL_TXQ_GROUP_VDEV_ID_BIT_MASK_GET(
2110 vdev_id_mask, vdev->vdev_id);
2111
2112 if (group_vdev_bit_mask != vdev_bit_mask) {
2113 /*
2114 * Change in vdev tx queue group
2115 */
2116 if (!vdev_bit_mask) {
2117 /* Set Group Pointer (vdev and peer) to NULL */
Nirav Shahaa34cbb2019-07-03 10:32:04 +05302118 ol_txrx_info("Group membership removed for vdev_id %d from group_id %d",
2119 vdev->vdev_id, group_id);
Nirav Shah52d85aa2018-04-26 14:03:00 +05302120 ol_tx_set_vdev_group_ptr(
2121 pdev, vdev->vdev_id, NULL);
2122 } else {
2123 /* Set Group Pointer (vdev and peer) */
Nirav Shahaa34cbb2019-07-03 10:32:04 +05302124 ol_txrx_info("Group membership updated for vdev_id %d to group_id %d",
2125 vdev->vdev_id, group_id);
Nirav Shah52d85aa2018-04-26 14:03:00 +05302126 ol_tx_set_vdev_group_ptr(
2127 pdev, vdev->vdev_id, group);
2128 }
2129 }
2130 }
2131 /* Update membership */
2132 group->membership = membership;
Nirav Shahaa34cbb2019-07-03 10:32:04 +05302133 ol_txrx_info("Group membership updated for group_id %d membership 0x%x",
2134 group_id, group->membership);
Nirav Shah52d85aa2018-04-26 14:03:00 +05302135credit_update:
2136 /* Update Credit */
2137 ol_txrx_update_group_credit(group, credit, absolute);
2138 qdf_spin_unlock_bh(&pdev->tx_queue_spinlock);
2139}
2140#endif
2141
2142#if defined(FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL) && \
2143 defined(FEATURE_HL_DBS_GROUP_CREDIT_SHARING)
2144#define MIN_INIT_GROUP_CREDITS 10
2145int ol_txrx_distribute_group_credits(struct ol_txrx_pdev_t *pdev,
2146 u8 group_id,
2147 u32 vdevid_mask_new)
2148{
2149 struct ol_tx_queue_group_t *grp = &pdev->txq_grps[group_id];
2150 struct ol_tx_queue_group_t *grp_nxt = &pdev->txq_grps[!group_id];
2151 int creds_nxt = qdf_atomic_read(&grp_nxt->credit);
2152 int vdevid_mask = OL_TXQ_GROUP_VDEV_ID_MASK_GET(grp->membership);
2153 int vdevid_mask_othgrp =
2154 OL_TXQ_GROUP_VDEV_ID_MASK_GET(grp_nxt->membership);
2155 int creds_distribute = 0;
2156
2157 /* if vdev added to the group is the first vdev */
2158 if ((vdevid_mask == 0) && (vdevid_mask_new != 0)) {
2159 /* if other group has members */
2160 if (vdevid_mask_othgrp) {
2161 if (creds_nxt < MIN_INIT_GROUP_CREDITS)
2162 creds_distribute = creds_nxt / 2;
2163 else
2164 creds_distribute = MIN_INIT_GROUP_CREDITS;
2165
2166 ol_txrx_update_group_credit(grp_nxt, -creds_distribute,
2167 0);
2168 } else {
2169 /*
2170 * Other grp has no members, give all credits to this
2171 * grp.
2172 */
2173 creds_distribute =
2174 qdf_atomic_read(&pdev->target_tx_credit);
2175 }
2176 /* if all vdevs are removed from this grp */
2177 } else if ((vdevid_mask != 0) && (vdevid_mask_new == 0)) {
2178 if (vdevid_mask_othgrp)
2179 /* Transfer credits to other grp */
2180 ol_txrx_update_group_credit(grp_nxt,
2181 qdf_atomic_read(&grp->
2182 credit),
2183 0);
2184 /* Set current grp credits to zero */
2185 ol_txrx_update_group_credit(grp, 0, 1);
2186 }
2187
2188 return creds_distribute;
2189}
2190#endif /*
2191 * FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL &&
2192 * FEATURE_HL_DBS_GROUP_CREDIT_SHARING
2193 */
2194
2195#ifdef QCA_HL_NETDEV_FLOW_CONTROL
Rakesh Pillaif94b1622019-11-07 19:54:01 +05302196int ol_txrx_register_hl_flow_control(struct cdp_soc_t *soc_hdl,
Rakesh Pillai6a36b0a2019-09-06 16:30:05 +05302197 uint8_t pdev_id,
Nirav Shah52d85aa2018-04-26 14:03:00 +05302198 tx_pause_callback flowcontrol)
2199{
Rakesh Pillaif94b1622019-11-07 19:54:01 +05302200 struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl);
Rakesh Pillaif94b1622019-11-07 19:54:01 +05302201 ol_txrx_pdev_handle pdev = ol_txrx_get_pdev_from_pdev_id(soc, pdev_id);
Rakesh Pillai6a36b0a2019-09-06 16:30:05 +05302202 u32 desc_pool_size;
Nirav Shah52d85aa2018-04-26 14:03:00 +05302203
Rakesh Pillai6a36b0a2019-09-06 16:30:05 +05302204 if (!pdev || !flowcontrol) {
2205 ol_txrx_err("pdev or pause_cb is NULL");
2206 return QDF_STATUS_E_INVAL;
2207 }
2208
2209 desc_pool_size = ol_tx_desc_pool_size_hl(pdev->ctrl_pdev);
Nirav Shah52d85aa2018-04-26 14:03:00 +05302210 /*
2211 * Assert if the tx descriptor pool size meets the requirements
2212 * Maximum 2 sessions are allowed on a band.
2213 */
2214 QDF_ASSERT((2 * ol_txrx_tx_desc_alloc_table[TXRX_FC_5GH_80M_2x2] +
2215 ol_txrx_tx_desc_alloc_table[TXRX_FC_2GH_40M_2x2])
2216 <= desc_pool_size);
2217
Nirav Shah52d85aa2018-04-26 14:03:00 +05302218 pdev->pause_cb = flowcontrol;
2219 return 0;
2220}
2221
Rakesh Pillaif94b1622019-11-07 19:54:01 +05302222int ol_txrx_set_vdev_os_queue_status(struct cdp_soc_t *soc_hdl, u8 vdev_id,
Nirav Shah52d85aa2018-04-26 14:03:00 +05302223 enum netif_action_type action)
2224{
2225 struct ol_txrx_vdev_t *vdev =
2226 (struct ol_txrx_vdev_t *)ol_txrx_get_vdev_from_vdev_id(vdev_id);
2227
2228 if (!vdev) {
2229 QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
2230 "%s: Invalid vdev_id %d", __func__, vdev_id);
2231 return -EINVAL;
2232 }
2233
2234 switch (action) {
2235 case WLAN_NETIF_PRIORITY_QUEUE_ON:
2236 qdf_spin_lock_bh(&vdev->pdev->tx_mutex);
2237 vdev->prio_q_paused = 0;
2238 qdf_spin_unlock_bh(&vdev->pdev->tx_mutex);
2239 break;
2240 case WLAN_WAKE_NON_PRIORITY_QUEUE:
2241 qdf_atomic_set(&vdev->os_q_paused, 0);
2242 break;
2243 default:
2244 QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
2245 "%s: Invalid action %d", __func__, action);
2246 return -EINVAL;
2247 }
2248 return 0;
2249}
2250
Rakesh Pillaif94b1622019-11-07 19:54:01 +05302251int ol_txrx_set_vdev_tx_desc_limit(struct cdp_soc_t *soc_hdl, u8 vdev_id,
2252 u8 chan)
Nirav Shah52d85aa2018-04-26 14:03:00 +05302253{
2254 struct ol_txrx_vdev_t *vdev =
2255 (struct ol_txrx_vdev_t *)ol_txrx_get_vdev_from_vdev_id(vdev_id);
2256 enum ol_txrx_fc_limit_id fc_limit_id;
2257 u32 td_limit;
2258
2259 if (!vdev) {
2260 QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
2261 "%s: Invalid vdev_id %d", __func__, vdev_id);
2262 return -EINVAL;
2263 }
2264
2265 /* TODO: Handle no of spatial streams and channel BW */
2266 if (WLAN_REG_IS_5GHZ_CH(chan))
2267 fc_limit_id = TXRX_FC_5GH_80M_2x2;
2268 else
2269 fc_limit_id = TXRX_FC_2GH_40M_2x2;
2270
2271 qdf_spin_lock_bh(&vdev->pdev->tx_mutex);
2272 td_limit = ol_txrx_tx_desc_alloc_table[fc_limit_id];
2273 vdev->tx_desc_limit = td_limit;
2274 vdev->queue_stop_th = td_limit - TXRX_HL_TX_DESC_HI_PRIO_RESERVED;
2275 vdev->queue_restart_th = td_limit - TXRX_HL_TX_DESC_QUEUE_RESTART_TH;
2276 qdf_spin_unlock_bh(&vdev->pdev->tx_mutex);
2277
2278 return 0;
2279}
Nirav Shahaa34cbb2019-07-03 10:32:04 +05302280
2281void ol_tx_dump_flow_pool_info_compact(void *ctx)
2282{
2283 struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
2284 char *comb_log_str;
2285 int bytes_written = 0;
2286 uint32_t free_size;
2287 struct ol_txrx_vdev_t *vdev;
2288 int i = 0;
2289
2290 free_size = WLAN_MAX_VDEVS * 100;
2291 comb_log_str = qdf_mem_malloc(free_size);
2292 if (!comb_log_str)
2293 return;
2294
2295 qdf_spin_lock_bh(&pdev->tx_mutex);
2296 TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) {
2297 bytes_written += snprintf(&comb_log_str[bytes_written],
2298 free_size, "%d (%d,%d)(%d,%d)(%d,%d) |",
2299 vdev->vdev_id, vdev->tx_desc_limit,
2300 qdf_atomic_read(&vdev->tx_desc_count),
2301 qdf_atomic_read(&vdev->os_q_paused),
2302 vdev->prio_q_paused, vdev->queue_stop_th,
2303 vdev->queue_restart_th);
2304 free_size -= bytes_written;
2305 }
2306 qdf_spin_unlock_bh(&pdev->tx_mutex);
2307 qdf_nofl_debug("STATS | FC: %s", comb_log_str);
2308
2309 free_size = WLAN_MAX_VDEVS * 100;
2310 bytes_written = 0;
2311 qdf_mem_zero(comb_log_str, free_size);
2312
2313 bytes_written = snprintf(&comb_log_str[bytes_written], free_size,
2314 "%d ",
2315 qdf_atomic_read(&pdev->target_tx_credit));
2316 for (i = 0; i < OL_TX_MAX_TXQ_GROUPS; i++) {
2317 bytes_written += snprintf(&comb_log_str[bytes_written],
2318 free_size, "|%d, (0x%x, %d)", i,
2319 OL_TXQ_GROUP_VDEV_ID_MASK_GET(
2320 pdev->txq_grps[i].membership),
2321 qdf_atomic_read(
2322 &pdev->txq_grps[i].credit));
2323 free_size -= bytes_written;
2324 }
2325 qdf_nofl_debug("STATS | CREDIT: %s", comb_log_str);
2326 qdf_mem_free(comb_log_str);
2327}
2328
Rakesh Pillaia889ffa2019-07-03 19:29:52 +05302329void ol_tx_dump_flow_pool_info(struct cdp_soc_t *soc_hdl)
Nirav Shahaa34cbb2019-07-03 10:32:04 +05302330{
Rakesh Pillaia889ffa2019-07-03 19:29:52 +05302331 struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl);
2332 ol_txrx_pdev_handle pdev;
Nirav Shahaa34cbb2019-07-03 10:32:04 +05302333 struct ol_txrx_vdev_t *vdev;
2334
Rakesh Pillaia889ffa2019-07-03 19:29:52 +05302335 pdev = ol_txrx_get_pdev_from_pdev_id(soc, OL_TXRX_PDEV_ID);
Nirav Shahaa34cbb2019-07-03 10:32:04 +05302336 if (!pdev) {
2337 ol_txrx_err("pdev is NULL");
2338 return;
2339 }
2340
2341 qdf_spin_lock_bh(&pdev->tx_mutex);
2342 TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) {
2343 txrx_nofl_info("vdev_id %d", vdev->vdev_id);
2344 txrx_nofl_info("limit %d available %d stop_threshold %d restart_threshold %d",
2345 vdev->tx_desc_limit,
2346 qdf_atomic_read(&vdev->tx_desc_count),
2347 vdev->queue_stop_th, vdev->queue_restart_th);
2348 txrx_nofl_info("q_paused %d prio_q_paused %d",
2349 qdf_atomic_read(&vdev->os_q_paused),
2350 vdev->prio_q_paused);
Nirav Shahfb9b1df2019-11-15 11:40:52 +05302351 txrx_nofl_info("no_of_bundle_sent_after_threshold %lld",
2352 vdev->no_of_bundle_sent_after_threshold);
2353 txrx_nofl_info("no_of_bundle_sent_in_timer %lld",
2354 vdev->no_of_bundle_sent_in_timer);
2355 txrx_nofl_info("no_of_pkt_not_added_in_queue %lld",
2356 vdev->no_of_pkt_not_added_in_queue);
Nirav Shahaa34cbb2019-07-03 10:32:04 +05302357 }
2358 qdf_spin_unlock_bh(&pdev->tx_mutex);
2359}
Nirav Shah52d85aa2018-04-26 14:03:00 +05302360#endif /* QCA_HL_NETDEV_FLOW_CONTROL */