1 /*
2 * Copyright (c) 2011-2019 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_data() - send data frame
47 * @soc_hdl: datapath soc handle
48 * @vdev_id: virtual interface id
49 * @skb: skb
50 *
51 * Return: skb/NULL for success
52 */
ol_tx_data(struct cdp_soc_t * soc_hdl,uint8_t vdev_id,qdf_nbuf_t skb)53 qdf_nbuf_t ol_tx_data(struct cdp_soc_t *soc_hdl, uint8_t vdev_id,
54 qdf_nbuf_t skb)
55 {
56 struct ol_txrx_pdev_t *pdev;
57 qdf_nbuf_t ret;
58 struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl);
59 ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_soc_vdev_id(soc,
60 vdev_id);
61
62 if (qdf_unlikely(!vdev)) {
63 QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG,
64 "%s:vdev is null", __func__);
65 return skb;
66 }
67
68 pdev = vdev->pdev;
69
70 if (qdf_unlikely(!pdev)) {
71 QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG,
72 "%s:pdev is null", __func__);
73 return skb;
74 }
75
76 if ((ol_cfg_is_ip_tcp_udp_checksum_offload_enabled(pdev->ctrl_pdev))
77 && (qdf_nbuf_get_protocol(skb) == htons(ETH_P_IP))
78 && (qdf_nbuf_get_ip_summed(skb) == CHECKSUM_PARTIAL))
79 qdf_nbuf_set_ip_summed(skb, CHECKSUM_COMPLETE);
80
81 /* Terminate the (single-element) list of tx frames */
82 qdf_nbuf_set_next(skb, NULL);
83 ret = OL_TX_SEND(vdev, skb);
84 if (ret) {
85 ol_txrx_dbg("Failed to tx");
86 return ret;
87 }
88
89 return NULL;
90 }
91
92 #ifdef IPA_OFFLOAD
ol_tx_send_ipa_data_frame(struct cdp_soc_t * soc_hdl,uint8_t vdev_id,qdf_nbuf_t skb)93 qdf_nbuf_t ol_tx_send_ipa_data_frame(struct cdp_soc_t *soc_hdl, uint8_t vdev_id,
94 qdf_nbuf_t skb)
95 {
96 struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl);
97 struct ol_txrx_pdev_t *pdev = ol_txrx_get_pdev_from_pdev_id(
98 soc, OL_TXRX_PDEV_ID);
99 ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_soc_vdev_id(soc,
100 vdev_id);
101 qdf_nbuf_t ret;
102
103 if (qdf_unlikely(!pdev)) {
104 ol_txrx_err("Invalid pdev");
105 return skb;
106 }
107 if (qdf_unlikely(!vdev)) {
108 ol_txrx_err("Invalid vdev, vdev_id:%d", vdev_id);
109 return skb;
110 }
111
112 if ((ol_cfg_is_ip_tcp_udp_checksum_offload_enabled(pdev->ctrl_pdev))
113 && (qdf_nbuf_get_protocol(skb) == htons(ETH_P_IP))
114 && (qdf_nbuf_get_ip_summed(skb) == CHECKSUM_PARTIAL))
115 qdf_nbuf_set_ip_summed(skb, CHECKSUM_COMPLETE);
116
117 /* Terminate the (single-element) list of tx frames */
118 qdf_nbuf_set_next(skb, NULL);
119
120 /*
121 * Add SKB to internal tracking table before further processing
122 * in WLAN driver.
123 */
124 qdf_net_buf_debug_acquire_skb(skb, __FILE__, __LINE__);
125
126 ret = OL_TX_SEND((struct ol_txrx_vdev_t *)vdev, skb);
127 if (ret) {
128 ol_txrx_dbg("Failed to tx");
129 return ret;
130 }
131
132 return NULL;
133 }
134 #endif
135
136 void
ol_txrx_data_tx_cb_set(struct cdp_soc_t * soc_hdl,uint8_t vdev_id,ol_txrx_data_tx_cb callback,void * ctxt)137 ol_txrx_data_tx_cb_set(struct cdp_soc_t *soc_hdl, uint8_t vdev_id,
138 ol_txrx_data_tx_cb callback, void *ctxt)
139 {
140 struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl);
141 ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_soc_vdev_id(soc,
142 vdev_id);
143 struct ol_txrx_pdev_t *pdev;
144
145 if (!vdev || !vdev->pdev)
146 return;
147
148 pdev = vdev->pdev;
149 pdev->tx_data_callback.func = callback;
150 pdev->tx_data_callback.ctxt = ctxt;
151 }
152
153 QDF_STATUS
ol_txrx_mgmt_tx_cb_set(struct cdp_soc_t * soc_hdl,uint8_t pdev_id,uint8_t type,ol_txrx_mgmt_tx_cb download_cb,ol_txrx_mgmt_tx_cb ota_ack_cb,void * ctxt)154 ol_txrx_mgmt_tx_cb_set(struct cdp_soc_t *soc_hdl, uint8_t pdev_id, uint8_t type,
155 ol_txrx_mgmt_tx_cb download_cb,
156 ol_txrx_mgmt_tx_cb ota_ack_cb, void *ctxt)
157 {
158 struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl);
159 struct ol_txrx_pdev_t *pdev = ol_txrx_get_pdev_from_pdev_id(soc,
160 pdev_id);
161
162 if (!pdev)
163 return QDF_STATUS_E_FAILURE;
164
165 TXRX_ASSERT1(type < OL_TXRX_MGMT_NUM_TYPES);
166 pdev->tx_mgmt_cb.download_cb = download_cb;
167 pdev->tx_mgmt_cb.ota_ack_cb = ota_ack_cb;
168 pdev->tx_mgmt_cb.ctxt = ctxt;
169
170 return QDF_STATUS_SUCCESS;
171 }
172
173 int
ol_txrx_mgmt_send_ext(struct cdp_soc_t * soc_hdl,uint8_t vdev_id,qdf_nbuf_t tx_mgmt_frm,uint8_t type,uint8_t use_6mbps,uint16_t chanfreq)174 ol_txrx_mgmt_send_ext(struct cdp_soc_t *soc_hdl, uint8_t vdev_id,
175 qdf_nbuf_t tx_mgmt_frm, uint8_t type,
176 uint8_t use_6mbps, uint16_t chanfreq)
177 {
178 struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl);
179 ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_soc_vdev_id(soc,
180 vdev_id);
181 struct ol_txrx_pdev_t *pdev;
182 struct ol_tx_desc_t *tx_desc;
183 struct ol_txrx_msdu_info_t tx_msdu_info;
184 int result = 0;
185
186 if (!vdev || !vdev->pdev)
187 return QDF_STATUS_E_FAULT;
188
189 pdev = vdev->pdev;
190 tx_msdu_info.tso_info.is_tso = 0;
191
192 tx_msdu_info.htt.action.use_6mbps = use_6mbps;
193 tx_msdu_info.htt.info.ext_tid = HTT_TX_EXT_TID_MGMT;
194 tx_msdu_info.htt.info.vdev_id = vdev->vdev_id;
195 tx_msdu_info.htt.action.do_tx_complete =
196 pdev->tx_mgmt_cb.ota_ack_cb ? 1 : 0;
197
198 /*
199 * FIX THIS: l2_hdr_type should only specify L2 header type
200 * The Peregrine/Rome HTT layer provides the FW with a "pkt type"
201 * that is a combination of L2 header type and 802.11 frame type.
202 * If the 802.11 frame type is "mgmt", then the HTT pkt type is "mgmt".
203 * But if the 802.11 frame type is "data", then the HTT pkt type is
204 * the L2 header type (more or less): 802.3 vs. Native WiFi
205 * (basic 802.11).
206 * (Or the header type can be "raw", which is any version of the 802.11
207 * header, and also implies that some of the offloaded tx data
208 * processing steps may not apply.)
209 * For efficiency, the Peregrine/Rome HTT uses the msdu_info's
210 * l2_hdr_type field to program the HTT pkt type. Thus, this txrx SW
211 * needs to overload the l2_hdr_type to indicate whether the frame is
212 * data vs. mgmt, as well as 802.3 L2 header vs. 802.11 L2 header.
213 * To fix this, the msdu_info's l2_hdr_type should be left specifying
214 * just the L2 header type. For mgmt frames, there should be a
215 * separate function to patch the HTT pkt type to store a "mgmt" value
216 * rather than the L2 header type. Then the HTT pkt type can be
217 * programmed efficiently for data frames, and the msdu_info's
218 * l2_hdr_type field won't be confusingly overloaded to hold the 802.11
219 * frame type rather than the L2 header type.
220 */
221 /*
222 * FIX THIS: remove duplication of htt_frm_type_mgmt and
223 * htt_pkt_type_mgmt
224 * The htt module expects a "enum htt_pkt_type" value.
225 * The htt_dxe module expects a "enum htt_frm_type" value.
226 * This needs to be cleaned up, so both versions of htt use a
227 * consistent method of specifying the frame type.
228 */
229 #ifdef QCA_SUPPORT_INTEGRATED_SOC
230 /* tx mgmt frames always come with a 802.11 header */
231 tx_msdu_info.htt.info.l2_hdr_type = htt_pkt_type_native_wifi;
232 tx_msdu_info.htt.info.frame_type = htt_frm_type_mgmt;
233 #else
234 tx_msdu_info.htt.info.l2_hdr_type = htt_pkt_type_mgmt;
235 tx_msdu_info.htt.info.frame_type = htt_pkt_type_mgmt;
236 #endif
237
238 tx_msdu_info.peer = NULL;
239
240 tx_desc = ol_txrx_mgmt_tx_desc_alloc(pdev, vdev, tx_mgmt_frm,
241 &tx_msdu_info);
242 if (!tx_desc)
243 return -EINVAL; /* can't accept the tx mgmt frame */
244
245 TXRX_STATS_MSDU_INCR(pdev, tx.mgmt, tx_mgmt_frm);
246 TXRX_ASSERT1(type < OL_TXRX_MGMT_NUM_TYPES);
247 tx_desc->pkt_type = type + OL_TXRX_MGMT_TYPE_BASE;
248
249 result = ol_txrx_mgmt_send_frame(vdev, tx_desc, tx_mgmt_frm,
250 &tx_msdu_info, chanfreq);
251
252 return 0; /* accepted the tx mgmt frame */
253 }
254