xref: /wlan-driver/qcacld-3.0/core/dp/txrx/ol_tx.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
1*5113495bSYour Name /*
2*5113495bSYour Name  * Copyright (c) 2011-2019 The Linux Foundation. All rights reserved.
3*5113495bSYour Name  * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
4*5113495bSYour Name  *
5*5113495bSYour Name  * Permission to use, copy, modify, and/or distribute this software for
6*5113495bSYour Name  * any purpose with or without fee is hereby granted, provided that the
7*5113495bSYour Name  * above copyright notice and this permission notice appear in all
8*5113495bSYour Name  * copies.
9*5113495bSYour Name  *
10*5113495bSYour Name  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11*5113495bSYour Name  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12*5113495bSYour Name  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13*5113495bSYour Name  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14*5113495bSYour Name  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15*5113495bSYour Name  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16*5113495bSYour Name  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17*5113495bSYour Name  * PERFORMANCE OF THIS SOFTWARE.
18*5113495bSYour Name  */
19*5113495bSYour Name 
20*5113495bSYour Name /* OS abstraction libraries */
21*5113495bSYour Name #include <qdf_nbuf.h>           /* qdf_nbuf_t, etc. */
22*5113495bSYour Name #include <qdf_atomic.h>         /* qdf_atomic_read, etc. */
23*5113495bSYour Name #include <qdf_util.h>           /* qdf_unlikely */
24*5113495bSYour Name 
25*5113495bSYour Name /* APIs for other modules */
26*5113495bSYour Name #include <htt.h>                /* HTT_TX_EXT_TID_MGMT */
27*5113495bSYour Name #include <ol_htt_tx_api.h>      /* htt_tx_desc_tid */
28*5113495bSYour Name 
29*5113495bSYour Name /* internal header files relevant for all systems */
30*5113495bSYour Name #include <ol_txrx_internal.h>   /* TXRX_ASSERT1 */
31*5113495bSYour Name #include <ol_tx_desc.h>         /* ol_tx_desc */
32*5113495bSYour Name #include <ol_tx_send.h>         /* ol_tx_send */
33*5113495bSYour Name #include <ol_txrx.h>
34*5113495bSYour Name 
35*5113495bSYour Name /* internal header files relevant only for HL systems */
36*5113495bSYour Name #include <ol_tx_classify.h>   /* ol_tx_classify, ol_tx_classify_mgmt */
37*5113495bSYour Name #include <ol_tx_queue.h>        /* ol_tx_enqueue */
38*5113495bSYour Name #include <ol_tx_sched.h>      /* ol_tx_sched */
39*5113495bSYour Name 
40*5113495bSYour Name /* internal header files relevant only for specific systems (Pronto) */
41*5113495bSYour Name #include <ol_txrx_encap.h>      /* OL_TX_ENCAP, etc */
42*5113495bSYour Name #include <ol_tx.h>
43*5113495bSYour Name #include <cdp_txrx_ipa.h>
44*5113495bSYour Name 
45*5113495bSYour Name /**
46*5113495bSYour Name  * ol_tx_data() - send data frame
47*5113495bSYour Name  * @soc_hdl: datapath soc handle
48*5113495bSYour Name  * @vdev_id: virtual interface id
49*5113495bSYour Name  * @skb: skb
50*5113495bSYour Name  *
51*5113495bSYour Name  * Return: skb/NULL for success
52*5113495bSYour Name  */
ol_tx_data(struct cdp_soc_t * soc_hdl,uint8_t vdev_id,qdf_nbuf_t skb)53*5113495bSYour Name qdf_nbuf_t ol_tx_data(struct cdp_soc_t *soc_hdl, uint8_t vdev_id,
54*5113495bSYour Name 		      qdf_nbuf_t skb)
55*5113495bSYour Name {
56*5113495bSYour Name 	struct ol_txrx_pdev_t *pdev;
57*5113495bSYour Name 	qdf_nbuf_t ret;
58*5113495bSYour Name 	struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl);
59*5113495bSYour Name 	ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_soc_vdev_id(soc,
60*5113495bSYour Name 								     vdev_id);
61*5113495bSYour Name 
62*5113495bSYour Name 	if (qdf_unlikely(!vdev)) {
63*5113495bSYour Name 		QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG,
64*5113495bSYour Name 			"%s:vdev is null", __func__);
65*5113495bSYour Name 		return skb;
66*5113495bSYour Name 	}
67*5113495bSYour Name 
68*5113495bSYour Name 	pdev = vdev->pdev;
69*5113495bSYour Name 
70*5113495bSYour Name 	if (qdf_unlikely(!pdev)) {
71*5113495bSYour Name 		QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG,
72*5113495bSYour Name 			"%s:pdev is null", __func__);
73*5113495bSYour Name 		return skb;
74*5113495bSYour Name 	}
75*5113495bSYour Name 
76*5113495bSYour Name 	if ((ol_cfg_is_ip_tcp_udp_checksum_offload_enabled(pdev->ctrl_pdev))
77*5113495bSYour Name 		&& (qdf_nbuf_get_protocol(skb) == htons(ETH_P_IP))
78*5113495bSYour Name 		&& (qdf_nbuf_get_ip_summed(skb) == CHECKSUM_PARTIAL))
79*5113495bSYour Name 		qdf_nbuf_set_ip_summed(skb, CHECKSUM_COMPLETE);
80*5113495bSYour Name 
81*5113495bSYour Name 	/* Terminate the (single-element) list of tx frames */
82*5113495bSYour Name 	qdf_nbuf_set_next(skb, NULL);
83*5113495bSYour Name 	ret = OL_TX_SEND(vdev, skb);
84*5113495bSYour Name 	if (ret) {
85*5113495bSYour Name 		ol_txrx_dbg("Failed to tx");
86*5113495bSYour Name 		return ret;
87*5113495bSYour Name 	}
88*5113495bSYour Name 
89*5113495bSYour Name 	return NULL;
90*5113495bSYour Name }
91*5113495bSYour Name 
92*5113495bSYour Name #ifdef IPA_OFFLOAD
ol_tx_send_ipa_data_frame(struct cdp_soc_t * soc_hdl,uint8_t vdev_id,qdf_nbuf_t skb)93*5113495bSYour Name qdf_nbuf_t ol_tx_send_ipa_data_frame(struct cdp_soc_t *soc_hdl, uint8_t vdev_id,
94*5113495bSYour Name 				     qdf_nbuf_t skb)
95*5113495bSYour Name {
96*5113495bSYour Name 	struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl);
97*5113495bSYour Name 	struct ol_txrx_pdev_t *pdev = ol_txrx_get_pdev_from_pdev_id(
98*5113495bSYour Name 							soc, OL_TXRX_PDEV_ID);
99*5113495bSYour Name 	ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_soc_vdev_id(soc,
100*5113495bSYour Name 								     vdev_id);
101*5113495bSYour Name 	qdf_nbuf_t ret;
102*5113495bSYour Name 
103*5113495bSYour Name 	if (qdf_unlikely(!pdev)) {
104*5113495bSYour Name 		ol_txrx_err("Invalid pdev");
105*5113495bSYour Name 		return skb;
106*5113495bSYour Name 	}
107*5113495bSYour Name 	if (qdf_unlikely(!vdev)) {
108*5113495bSYour Name 		ol_txrx_err("Invalid vdev, vdev_id:%d", vdev_id);
109*5113495bSYour Name 		return skb;
110*5113495bSYour Name 	}
111*5113495bSYour Name 
112*5113495bSYour Name 	if ((ol_cfg_is_ip_tcp_udp_checksum_offload_enabled(pdev->ctrl_pdev))
113*5113495bSYour Name 		&& (qdf_nbuf_get_protocol(skb) == htons(ETH_P_IP))
114*5113495bSYour Name 		&& (qdf_nbuf_get_ip_summed(skb) == CHECKSUM_PARTIAL))
115*5113495bSYour Name 		qdf_nbuf_set_ip_summed(skb, CHECKSUM_COMPLETE);
116*5113495bSYour Name 
117*5113495bSYour Name 	/* Terminate the (single-element) list of tx frames */
118*5113495bSYour Name 	qdf_nbuf_set_next(skb, NULL);
119*5113495bSYour Name 
120*5113495bSYour Name 	/*
121*5113495bSYour Name 	 * Add SKB to internal tracking table before further processing
122*5113495bSYour Name 	 * in WLAN driver.
123*5113495bSYour Name 	 */
124*5113495bSYour Name 	qdf_net_buf_debug_acquire_skb(skb, __FILE__, __LINE__);
125*5113495bSYour Name 
126*5113495bSYour Name 	ret = OL_TX_SEND((struct ol_txrx_vdev_t *)vdev, skb);
127*5113495bSYour Name 	if (ret) {
128*5113495bSYour Name 		ol_txrx_dbg("Failed to tx");
129*5113495bSYour Name 		return ret;
130*5113495bSYour Name 	}
131*5113495bSYour Name 
132*5113495bSYour Name 	return NULL;
133*5113495bSYour Name }
134*5113495bSYour Name #endif
135*5113495bSYour Name 
136*5113495bSYour Name 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*5113495bSYour Name ol_txrx_data_tx_cb_set(struct cdp_soc_t *soc_hdl, uint8_t vdev_id,
138*5113495bSYour Name 		       ol_txrx_data_tx_cb callback, void *ctxt)
139*5113495bSYour Name {
140*5113495bSYour Name 	struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl);
141*5113495bSYour Name 	ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_soc_vdev_id(soc,
142*5113495bSYour Name 								     vdev_id);
143*5113495bSYour Name 	struct ol_txrx_pdev_t *pdev;
144*5113495bSYour Name 
145*5113495bSYour Name 	if (!vdev || !vdev->pdev)
146*5113495bSYour Name 		return;
147*5113495bSYour Name 
148*5113495bSYour Name 	pdev = vdev->pdev;
149*5113495bSYour Name 	pdev->tx_data_callback.func = callback;
150*5113495bSYour Name 	pdev->tx_data_callback.ctxt = ctxt;
151*5113495bSYour Name }
152*5113495bSYour Name 
153*5113495bSYour Name 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*5113495bSYour Name ol_txrx_mgmt_tx_cb_set(struct cdp_soc_t *soc_hdl, uint8_t pdev_id, uint8_t type,
155*5113495bSYour Name 		       ol_txrx_mgmt_tx_cb download_cb,
156*5113495bSYour Name 		       ol_txrx_mgmt_tx_cb ota_ack_cb, void *ctxt)
157*5113495bSYour Name {
158*5113495bSYour Name 	struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl);
159*5113495bSYour Name 	struct ol_txrx_pdev_t *pdev = ol_txrx_get_pdev_from_pdev_id(soc,
160*5113495bSYour Name 								    pdev_id);
161*5113495bSYour Name 
162*5113495bSYour Name 	if (!pdev)
163*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
164*5113495bSYour Name 
165*5113495bSYour Name 	TXRX_ASSERT1(type < OL_TXRX_MGMT_NUM_TYPES);
166*5113495bSYour Name 	pdev->tx_mgmt_cb.download_cb = download_cb;
167*5113495bSYour Name 	pdev->tx_mgmt_cb.ota_ack_cb = ota_ack_cb;
168*5113495bSYour Name 	pdev->tx_mgmt_cb.ctxt = ctxt;
169*5113495bSYour Name 
170*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
171*5113495bSYour Name }
172*5113495bSYour Name 
173*5113495bSYour Name 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*5113495bSYour Name ol_txrx_mgmt_send_ext(struct cdp_soc_t *soc_hdl, uint8_t vdev_id,
175*5113495bSYour Name 		      qdf_nbuf_t tx_mgmt_frm, uint8_t type,
176*5113495bSYour Name 		      uint8_t use_6mbps, uint16_t chanfreq)
177*5113495bSYour Name {
178*5113495bSYour Name 	struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl);
179*5113495bSYour Name 	ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_soc_vdev_id(soc,
180*5113495bSYour Name 								     vdev_id);
181*5113495bSYour Name 	struct ol_txrx_pdev_t *pdev;
182*5113495bSYour Name 	struct ol_tx_desc_t *tx_desc;
183*5113495bSYour Name 	struct ol_txrx_msdu_info_t tx_msdu_info;
184*5113495bSYour Name 	int result = 0;
185*5113495bSYour Name 
186*5113495bSYour Name 	if (!vdev || !vdev->pdev)
187*5113495bSYour Name 		return QDF_STATUS_E_FAULT;
188*5113495bSYour Name 
189*5113495bSYour Name 	pdev = vdev->pdev;
190*5113495bSYour Name 	tx_msdu_info.tso_info.is_tso = 0;
191*5113495bSYour Name 
192*5113495bSYour Name 	tx_msdu_info.htt.action.use_6mbps = use_6mbps;
193*5113495bSYour Name 	tx_msdu_info.htt.info.ext_tid = HTT_TX_EXT_TID_MGMT;
194*5113495bSYour Name 	tx_msdu_info.htt.info.vdev_id = vdev->vdev_id;
195*5113495bSYour Name 	tx_msdu_info.htt.action.do_tx_complete =
196*5113495bSYour Name 		pdev->tx_mgmt_cb.ota_ack_cb ? 1 : 0;
197*5113495bSYour Name 
198*5113495bSYour Name 	/*
199*5113495bSYour Name 	 * FIX THIS: l2_hdr_type should only specify L2 header type
200*5113495bSYour Name 	 * The Peregrine/Rome HTT layer provides the FW with a "pkt type"
201*5113495bSYour Name 	 * that is a combination of L2 header type and 802.11 frame type.
202*5113495bSYour Name 	 * If the 802.11 frame type is "mgmt", then the HTT pkt type is "mgmt".
203*5113495bSYour Name 	 * But if the 802.11 frame type is "data", then the HTT pkt type is
204*5113495bSYour Name 	 * the L2 header type (more or less): 802.3 vs. Native WiFi
205*5113495bSYour Name 	 * (basic 802.11).
206*5113495bSYour Name 	 * (Or the header type can be "raw", which is any version of the 802.11
207*5113495bSYour Name 	 * header, and also implies that some of the offloaded tx data
208*5113495bSYour Name 	 * processing steps may not apply.)
209*5113495bSYour Name 	 * For efficiency, the Peregrine/Rome HTT uses the msdu_info's
210*5113495bSYour Name 	 * l2_hdr_type field to program the HTT pkt type.  Thus, this txrx SW
211*5113495bSYour Name 	 * needs to overload the l2_hdr_type to indicate whether the frame is
212*5113495bSYour Name 	 * data vs. mgmt, as well as 802.3 L2 header vs. 802.11 L2 header.
213*5113495bSYour Name 	 * To fix this, the msdu_info's l2_hdr_type should be left specifying
214*5113495bSYour Name 	 * just the L2 header type.  For mgmt frames, there should be a
215*5113495bSYour Name 	 * separate function to patch the HTT pkt type to store a "mgmt" value
216*5113495bSYour Name 	 * rather than the L2 header type.  Then the HTT pkt type can be
217*5113495bSYour Name 	 * programmed efficiently for data frames, and the msdu_info's
218*5113495bSYour Name 	 * l2_hdr_type field won't be confusingly overloaded to hold the 802.11
219*5113495bSYour Name 	 * frame type rather than the L2 header type.
220*5113495bSYour Name 	 */
221*5113495bSYour Name 	/*
222*5113495bSYour Name 	 * FIX THIS: remove duplication of htt_frm_type_mgmt and
223*5113495bSYour Name 	 * htt_pkt_type_mgmt
224*5113495bSYour Name 	 * The htt module expects a "enum htt_pkt_type" value.
225*5113495bSYour Name 	 * The htt_dxe module expects a "enum htt_frm_type" value.
226*5113495bSYour Name 	 * This needs to be cleaned up, so both versions of htt use a
227*5113495bSYour Name 	 * consistent method of specifying the frame type.
228*5113495bSYour Name 	 */
229*5113495bSYour Name #ifdef QCA_SUPPORT_INTEGRATED_SOC
230*5113495bSYour Name 	/* tx mgmt frames always come with a 802.11 header */
231*5113495bSYour Name 	tx_msdu_info.htt.info.l2_hdr_type = htt_pkt_type_native_wifi;
232*5113495bSYour Name 	tx_msdu_info.htt.info.frame_type = htt_frm_type_mgmt;
233*5113495bSYour Name #else
234*5113495bSYour Name 	tx_msdu_info.htt.info.l2_hdr_type = htt_pkt_type_mgmt;
235*5113495bSYour Name 	tx_msdu_info.htt.info.frame_type = htt_pkt_type_mgmt;
236*5113495bSYour Name #endif
237*5113495bSYour Name 
238*5113495bSYour Name 	tx_msdu_info.peer = NULL;
239*5113495bSYour Name 
240*5113495bSYour Name 	tx_desc = ol_txrx_mgmt_tx_desc_alloc(pdev, vdev, tx_mgmt_frm,
241*5113495bSYour Name 							&tx_msdu_info);
242*5113495bSYour Name 	if (!tx_desc)
243*5113495bSYour Name 		return -EINVAL;       /* can't accept the tx mgmt frame */
244*5113495bSYour Name 
245*5113495bSYour Name 	TXRX_STATS_MSDU_INCR(pdev, tx.mgmt, tx_mgmt_frm);
246*5113495bSYour Name 	TXRX_ASSERT1(type < OL_TXRX_MGMT_NUM_TYPES);
247*5113495bSYour Name 	tx_desc->pkt_type = type + OL_TXRX_MGMT_TYPE_BASE;
248*5113495bSYour Name 
249*5113495bSYour Name 	result = ol_txrx_mgmt_send_frame(vdev, tx_desc, tx_mgmt_frm,
250*5113495bSYour Name 						&tx_msdu_info, chanfreq);
251*5113495bSYour Name 
252*5113495bSYour Name 	return 0;               /* accepted the tx mgmt frame */
253*5113495bSYour Name }
254