1 /*
2 * Copyright (c) 2011-2018,The Linux Foundation. All rights reserved.
3 * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for
6 * any purpose with or without fee is hereby granted, provided that the
7 * above copyright notice and this permission notice appear in all
8 * copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 /* OS abstraction libraries */
21 #include <qdf_nbuf.h> /* qdf_nbuf_t, etc. */
22 #include <qdf_atomic.h> /* qdf_atomic_read, etc. */
23 #include <qdf_util.h> /* qdf_unlikely */
24
25 /* APIs for other modules */
26 #include <htt.h> /* HTT_TX_EXT_TID_MGMT */
27 #include <ol_htt_tx_api.h> /* htt_tx_desc_tid */
28
29 /* internal header files relevant for all systems */
30 #include <ol_txrx_internal.h> /* TXRX_ASSERT1 */
31 #include <ol_tx_desc.h> /* ol_tx_desc */
32 #include <ol_tx_send.h> /* ol_tx_send */
33 #include <ol_txrx.h>
34
35 /* internal header files relevant only for HL systems */
36 #include <ol_tx_classify.h> /* ol_tx_classify, ol_tx_classify_mgmt */
37 #include <ol_tx_queue.h> /* ol_tx_enqueue */
38 #include <ol_tx_sched.h> /* ol_tx_sched */
39
40 /* internal header files relevant only for specific systems (Pronto) */
41 #include <ol_txrx_encap.h> /* OL_TX_ENCAP, etc */
42 #include <ol_tx.h>
43 #include <cdp_txrx_ipa.h>
44
45 /**
46 * ol_tx_ll_wrapper() wrapper to ol_tx_ll
47 *
48 */
49 qdf_nbuf_t
ol_tx_ll_wrapper(ol_txrx_vdev_handle vdev,qdf_nbuf_t msdu_list)50 ol_tx_ll_wrapper(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list)
51 {
52 return ol_tx_ll(vdev, msdu_list);
53 }
54
55 #if defined(FEATURE_TSO)
ol_tx_ll(ol_txrx_vdev_handle vdev,qdf_nbuf_t msdu_list)56 qdf_nbuf_t ol_tx_ll(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list)
57 {
58 qdf_nbuf_t msdu = msdu_list;
59 struct ol_txrx_msdu_info_t msdu_info;
60 uint32_t tso_msdu_stats_idx = 0;
61
62 msdu_info.htt.info.l2_hdr_type = vdev->pdev->htt_pkt_type;
63 msdu_info.htt.action.tx_comp_req = 0;
64 /*
65 * The msdu_list variable could be used instead of the msdu var,
66 * but just to clarify which operations are done on a single MSDU
67 * vs. a list of MSDUs, use a distinct variable for single MSDUs
68 * within the list.
69 */
70 while (msdu) {
71 qdf_nbuf_t next;
72 struct ol_tx_desc_t *tx_desc = NULL;
73 int segments = 1;
74
75 msdu_info.htt.info.ext_tid = qdf_nbuf_get_tid(msdu);
76 msdu_info.peer = NULL;
77
78 if (qdf_unlikely(ol_tx_prepare_tso(vdev, msdu, &msdu_info))) {
79 qdf_print("ol_tx_prepare_tso failed\n");
80 TXRX_STATS_MSDU_LIST_INCR(vdev->pdev,
81 tx.dropped.host_reject,
82 msdu);
83 return msdu;
84 }
85
86 segments = msdu_info.tso_info.num_segs;
87
88 if (msdu_info.tso_info.is_tso) {
89 tso_msdu_stats_idx =
90 ol_tx_tso_get_stats_idx(vdev->pdev);
91 msdu_info.tso_info.msdu_stats_idx = tso_msdu_stats_idx;
92 ol_tx_tso_update_stats(vdev->pdev,
93 &(msdu_info.tso_info),
94 msdu, tso_msdu_stats_idx);
95 }
96
97 /*
98 * The netbuf may get linked into a different list inside the
99 * ol_tx_send function, so store the next pointer before the
100 * tx_send call.
101 */
102 next = qdf_nbuf_next(msdu);
103 /* init the current segment to the 1st segment in the list */
104 while (segments) {
105 if (msdu_info.tso_info.curr_seg)
106 QDF_NBUF_CB_PADDR(msdu) =
107 msdu_info.tso_info.curr_seg->
108 seg.tso_frags[0].paddr;
109
110 segments--;
111
112 tx_desc = ol_tx_prepare_ll(vdev, msdu, &msdu_info);
113 if (!tx_desc)
114 return msdu;
115
116 ol_tx_trace_pkt(msdu, tx_desc->id, vdev->vdev_id,
117 vdev->qdf_opmode);
118
119 /*
120 * If this is a jumbo nbuf, then increment the number
121 * of nbuf users for each additional segment of the msdu
122 * This will ensure that the skb is freed only after
123 * receiving tx completion for all segments of an nbuf.
124 */
125 if (segments)
126 qdf_nbuf_inc_users(msdu);
127
128 TXRX_STATS_MSDU_INCR(vdev->pdev, tx.from_stack, msdu);
129
130 /*
131 * If debug display is enabled, show the meta-data being
132 * downloaded to the target via the HTT tx descriptor.
133 */
134 htt_tx_desc_display(tx_desc->htt_tx_desc);
135
136 ol_tx_send(vdev->pdev, tx_desc, msdu, vdev->vdev_id);
137
138 if (msdu_info.tso_info.curr_seg) {
139 msdu_info.tso_info.curr_seg =
140 msdu_info.tso_info.curr_seg->next;
141 }
142
143 if (msdu_info.tso_info.is_tso) {
144 TXRX_STATS_TSO_INC_SEG(vdev->pdev,
145 tso_msdu_stats_idx);
146 TXRX_STATS_TSO_INC_SEG_IDX(vdev->pdev,
147 tso_msdu_stats_idx);
148 }
149 } /* while segments */
150
151 msdu = next;
152 } /* while msdus */
153 return NULL; /* all MSDUs were accepted */
154 }
155 #else /* TSO */
156
ol_tx_ll(ol_txrx_vdev_handle vdev,qdf_nbuf_t msdu_list)157 qdf_nbuf_t ol_tx_ll(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list)
158 {
159 qdf_nbuf_t msdu = msdu_list;
160 struct ol_txrx_msdu_info_t msdu_info;
161
162 msdu_info.htt.info.l2_hdr_type = vdev->pdev->htt_pkt_type;
163 msdu_info.htt.action.tx_comp_req = 0;
164 msdu_info.tso_info.is_tso = 0;
165 /*
166 * The msdu_list variable could be used instead of the msdu var,
167 * but just to clarify which operations are done on a single MSDU
168 * vs. a list of MSDUs, use a distinct variable for single MSDUs
169 * within the list.
170 */
171 while (msdu) {
172 qdf_nbuf_t next;
173 struct ol_tx_desc_t *tx_desc = NULL;
174
175 msdu_info.htt.info.ext_tid = qdf_nbuf_get_tid(msdu);
176 msdu_info.peer = NULL;
177 tx_desc = ol_tx_prepare_ll(vdev, msdu, &msdu_info);
178 if (!tx_desc)
179 return msdu;
180
181 ol_tx_trace_pkt(msdu, tx_desc->id, vdev->vdev_id,
182 vdev->qdf_opmode);
183
184 TXRX_STATS_MSDU_INCR(vdev->pdev, tx.from_stack, msdu);
185
186 /*
187 * If debug display is enabled, show the meta-data being
188 * downloaded to the target via the HTT tx descriptor.
189 */
190 htt_tx_desc_display(tx_desc->htt_tx_desc);
191 /*
192 * The netbuf may get linked into a different list inside the
193 * ol_tx_send function, so store the next pointer before the
194 * tx_send call.
195 */
196 next = qdf_nbuf_next(msdu);
197 ol_tx_send(vdev->pdev, tx_desc, msdu, vdev->vdev_id);
198 msdu = next;
199 }
200 return NULL; /* all MSDUs were accepted */
201 }
202 #endif /* TSO */
203