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