xref: /wlan-driver/qcacld-3.0/os_if/dp/src/os_if_dp_txrx.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
1*5113495bSYour Name /*
2*5113495bSYour Name  * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
3*5113495bSYour Name  *
4*5113495bSYour Name  * Permission to use, copy, modify, and/or distribute this software for any
5*5113495bSYour Name  * purpose with or without fee is hereby granted, provided that the above
6*5113495bSYour Name  * copyright notice and this permission notice appear in all copies.
7*5113495bSYour Name  *
8*5113495bSYour Name  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9*5113495bSYour Name  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10*5113495bSYour Name  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11*5113495bSYour Name  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12*5113495bSYour Name  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13*5113495bSYour Name  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14*5113495bSYour Name  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15*5113495bSYour Name  */
16*5113495bSYour Name 
17*5113495bSYour Name /**
18*5113495bSYour Name  *  DOC: osif_dp_txrx.c
19*5113495bSYour Name  *  This file contains DP component's TX/RX osif API implementation
20*5113495bSYour Name  */
21*5113495bSYour Name #include "os_if_dp.h"
22*5113495bSYour Name #include "os_if_dp_lro.h"
23*5113495bSYour Name #include <wlan_dp_public_struct.h>
24*5113495bSYour Name #include <wlan_objmgr_vdev_obj.h>
25*5113495bSYour Name #include "osif_sync.h"
26*5113495bSYour Name #include <linux/netdevice.h>
27*5113495bSYour Name #include <linux/skbuff.h>
28*5113495bSYour Name #include <linux/etherdevice.h>
29*5113495bSYour Name #include <linux/if_ether.h>
30*5113495bSYour Name #include <linux/inetdevice.h>
31*5113495bSYour Name #include <linux/wireless.h>
32*5113495bSYour Name #include <linux/rtnetlink.h>
33*5113495bSYour Name #include <net/cfg80211.h>
34*5113495bSYour Name #include <cdp_txrx_cmn.h>
35*5113495bSYour Name #include <cdp_txrx_peer_ops.h>
36*5113495bSYour Name #include <cdp_txrx_misc.h>
37*5113495bSYour Name #include <net/tcp.h>
38*5113495bSYour Name #include <ol_defines.h>
39*5113495bSYour Name #include <hif_napi.h>
40*5113495bSYour Name #include <hif.h>
41*5113495bSYour Name #include <wlan_hdd_main.h>
42*5113495bSYour Name #include "wlan_hdd_wmm.h"
43*5113495bSYour Name 
44*5113495bSYour Name /**
45*5113495bSYour Name  * osif_dp_classify_pkt() - classify packet
46*5113495bSYour Name  * @skb:  sk buff
47*5113495bSYour Name  *
48*5113495bSYour Name  * Return: none
49*5113495bSYour Name  */
osif_dp_classify_pkt(struct sk_buff * skb)50*5113495bSYour Name void osif_dp_classify_pkt(struct sk_buff *skb)
51*5113495bSYour Name {
52*5113495bSYour Name 	struct ethhdr *eh = (struct ethhdr *)skb->data;
53*5113495bSYour Name 
54*5113495bSYour Name 	qdf_mem_zero(skb->cb, sizeof(skb->cb));
55*5113495bSYour Name 
56*5113495bSYour Name 	/* check destination mac address is broadcast/multicast */
57*5113495bSYour Name 	if (is_broadcast_ether_addr((uint8_t *)eh))
58*5113495bSYour Name 		QDF_NBUF_CB_GET_IS_BCAST(skb) = true;
59*5113495bSYour Name 	else if (is_multicast_ether_addr((uint8_t *)eh))
60*5113495bSYour Name 		QDF_NBUF_CB_GET_IS_MCAST(skb) = true;
61*5113495bSYour Name 
62*5113495bSYour Name 	if (qdf_nbuf_is_ipv4_arp_pkt(skb))
63*5113495bSYour Name 		QDF_NBUF_CB_GET_PACKET_TYPE(skb) =
64*5113495bSYour Name 			QDF_NBUF_CB_PACKET_TYPE_ARP;
65*5113495bSYour Name 	else if (qdf_nbuf_is_ipv4_dhcp_pkt(skb))
66*5113495bSYour Name 		QDF_NBUF_CB_GET_PACKET_TYPE(skb) =
67*5113495bSYour Name 			QDF_NBUF_CB_PACKET_TYPE_DHCP;
68*5113495bSYour Name 	else if (qdf_nbuf_is_ipv4_eapol_pkt(skb))
69*5113495bSYour Name 		QDF_NBUF_CB_GET_PACKET_TYPE(skb) =
70*5113495bSYour Name 			QDF_NBUF_CB_PACKET_TYPE_EAPOL;
71*5113495bSYour Name 	else if (qdf_nbuf_is_ipv4_wapi_pkt(skb))
72*5113495bSYour Name 		QDF_NBUF_CB_GET_PACKET_TYPE(skb) =
73*5113495bSYour Name 			QDF_NBUF_CB_PACKET_TYPE_WAPI;
74*5113495bSYour Name 	else if (qdf_nbuf_is_icmp_pkt(skb))
75*5113495bSYour Name 		QDF_NBUF_CB_GET_PACKET_TYPE(skb) =
76*5113495bSYour Name 			QDF_NBUF_CB_PACKET_TYPE_ICMP;
77*5113495bSYour Name 	else if (qdf_nbuf_is_icmpv6_pkt(skb))
78*5113495bSYour Name 		QDF_NBUF_CB_GET_PACKET_TYPE(skb) =
79*5113495bSYour Name 			QDF_NBUF_CB_PACKET_TYPE_ICMPv6;
80*5113495bSYour Name }
81*5113495bSYour Name 
82*5113495bSYour Name /**
83*5113495bSYour Name  * osif_dp_mark_critical_pkt() - Identify and mark critical packets
84*5113495bSYour Name  * @skb: skb ptr
85*5113495bSYour Name  *
86*5113495bSYour Name  * Return: None
87*5113495bSYour Name  */
osif_dp_mark_critical_pkt(struct sk_buff * skb)88*5113495bSYour Name static void osif_dp_mark_critical_pkt(struct sk_buff *skb)
89*5113495bSYour Name {
90*5113495bSYour Name 	if (qdf_nbuf_is_ipv4_eapol_pkt(skb)) {
91*5113495bSYour Name 		QDF_NBUF_CB_GET_PACKET_TYPE(skb) =
92*5113495bSYour Name 				QDF_NBUF_CB_PACKET_TYPE_EAPOL;
93*5113495bSYour Name 	} else if (qdf_nbuf_is_ipv4_arp_pkt(skb)) {
94*5113495bSYour Name 		QDF_NBUF_CB_GET_PACKET_TYPE(skb) =
95*5113495bSYour Name 				QDF_NBUF_CB_PACKET_TYPE_ARP;
96*5113495bSYour Name 	} else if (qdf_nbuf_is_ipv4_dhcp_pkt(skb)) {
97*5113495bSYour Name 		QDF_NBUF_CB_GET_PACKET_TYPE(skb) =
98*5113495bSYour Name 				QDF_NBUF_CB_PACKET_TYPE_DHCP;
99*5113495bSYour Name 	} else if (qdf_nbuf_is_ipv6_dhcp_pkt(skb)) {
100*5113495bSYour Name 		QDF_NBUF_CB_GET_PACKET_TYPE(skb) =
101*5113495bSYour Name 				QDF_NBUF_CB_PACKET_TYPE_DHCPV6;
102*5113495bSYour Name 	} else if (qdf_nbuf_is_icmpv6_pkt(skb)) {
103*5113495bSYour Name 		QDF_NBUF_CB_GET_PACKET_TYPE(skb) =
104*5113495bSYour Name 			QDF_NBUF_CB_PACKET_TYPE_ICMPv6;
105*5113495bSYour Name 	}
106*5113495bSYour Name 
107*5113495bSYour Name 	QDF_NBUF_CB_TX_EXTRA_IS_CRITICAL(skb) = true;
108*5113495bSYour Name }
109*5113495bSYour Name 
110*5113495bSYour Name #ifdef DP_TX_PACKET_INSPECT_FOR_ILP
111*5113495bSYour Name /**
112*5113495bSYour Name  * osif_dp_mark_pkt_type_by_priority() - mark packet type to skb->cb
113*5113495bSYour Name  *                                       by type from priority of skb
114*5113495bSYour Name  * @skb: network buffer
115*5113495bSYour Name  *
116*5113495bSYour Name  * Return: true - packet type marked, false - not marked
117*5113495bSYour Name  */
118*5113495bSYour Name static inline
osif_dp_mark_pkt_type_by_priority(struct sk_buff * skb)119*5113495bSYour Name bool osif_dp_mark_pkt_type_by_priority(struct sk_buff *skb)
120*5113495bSYour Name {
121*5113495bSYour Name 	bool type_marked = false;
122*5113495bSYour Name 	uint32_t pkt_type =
123*5113495bSYour Name 		qdf_nbuf_get_priority_pkt_type(skb);
124*5113495bSYour Name 
125*5113495bSYour Name 	if (qdf_unlikely(pkt_type == QDF_NBUF_PRIORITY_PKT_TCP_ACK)) {
126*5113495bSYour Name 		QDF_NBUF_CB_GET_PACKET_TYPE(skb) =
127*5113495bSYour Name 					QDF_NBUF_CB_PACKET_TYPE_TCP_ACK;
128*5113495bSYour Name 		type_marked = true;
129*5113495bSYour Name 	}
130*5113495bSYour Name 	/* cleanup the packet type in priority */
131*5113495bSYour Name 	qdf_nbuf_remove_priority_pkt_type(skb);
132*5113495bSYour Name 
133*5113495bSYour Name 	return type_marked;
134*5113495bSYour Name }
135*5113495bSYour Name #else
136*5113495bSYour Name static inline
osif_dp_mark_pkt_type_by_priority(struct sk_buff * skb)137*5113495bSYour Name bool osif_dp_mark_pkt_type_by_priority(struct sk_buff *skb)
138*5113495bSYour Name {
139*5113495bSYour Name 	return false;
140*5113495bSYour Name }
141*5113495bSYour Name #endif
142*5113495bSYour Name 
143*5113495bSYour Name /**
144*5113495bSYour Name  * osif_dp_mark_non_critical_pkt() - Identify and mark non-critical packets
145*5113495bSYour Name  * @skb: skb ptr
146*5113495bSYour Name  *
147*5113495bSYour Name  * Return: None
148*5113495bSYour Name  */
osif_dp_mark_non_critical_pkt(struct sk_buff * skb)149*5113495bSYour Name static void osif_dp_mark_non_critical_pkt(struct sk_buff *skb)
150*5113495bSYour Name {
151*5113495bSYour Name 	/* check if packet type is marked from skb->priority already */
152*5113495bSYour Name 	if (osif_dp_mark_pkt_type_by_priority(skb))
153*5113495bSYour Name 		return;
154*5113495bSYour Name 
155*5113495bSYour Name 	if (qdf_nbuf_is_icmp_pkt(skb))
156*5113495bSYour Name 		QDF_NBUF_CB_GET_PACKET_TYPE(skb) =
157*5113495bSYour Name 				QDF_NBUF_CB_PACKET_TYPE_ICMP;
158*5113495bSYour Name 	else if (qdf_nbuf_is_ipv4_wapi_pkt(skb))
159*5113495bSYour Name 		QDF_NBUF_CB_GET_PACKET_TYPE(skb) =
160*5113495bSYour Name 			QDF_NBUF_CB_PACKET_TYPE_WAPI;
161*5113495bSYour Name }
162*5113495bSYour Name 
osif_dp_mark_pkt_type(struct sk_buff * skb)163*5113495bSYour Name void osif_dp_mark_pkt_type(struct sk_buff *skb)
164*5113495bSYour Name {
165*5113495bSYour Name 	struct ethhdr *eh = (struct ethhdr *)skb->data;
166*5113495bSYour Name 
167*5113495bSYour Name 	/*
168*5113495bSYour Name 	 * Zero out CB before accessing it. Expectation is that cb is accessed
169*5113495bSYour Name 	 * for the first time here on TX path in hard_start_xmit.
170*5113495bSYour Name 	 */
171*5113495bSYour Name 	qdf_mem_zero(skb->cb, sizeof(skb->cb));
172*5113495bSYour Name 
173*5113495bSYour Name 	/* check destination mac address is broadcast/multicast */
174*5113495bSYour Name 	if (is_broadcast_ether_addr((uint8_t *)eh))
175*5113495bSYour Name 		QDF_NBUF_CB_GET_IS_BCAST(skb) = true;
176*5113495bSYour Name 	else if (is_multicast_ether_addr((uint8_t *)eh))
177*5113495bSYour Name 		QDF_NBUF_CB_GET_IS_MCAST(skb) = true;
178*5113495bSYour Name 
179*5113495bSYour Name 	/*
180*5113495bSYour Name 	 * TX Packets in the HI_PRIO queue are assumed to be critical and
181*5113495bSYour Name 	 * marked accordingly.
182*5113495bSYour Name 	 */
183*5113495bSYour Name 	if (skb->queue_mapping == TX_GET_QUEUE_IDX(HDD_LINUX_AC_HI_PRIO, 0))
184*5113495bSYour Name 		osif_dp_mark_critical_pkt(skb);
185*5113495bSYour Name 	else
186*5113495bSYour Name 		osif_dp_mark_non_critical_pkt(skb);
187*5113495bSYour Name }
188*5113495bSYour Name 
189*5113495bSYour Name /*
190*5113495bSYour Name  * When bus bandwidth is idle, if RX data is delivered with
191*5113495bSYour Name  * napi_gro_receive, to reduce RX delay related with GRO,
192*5113495bSYour Name  * check gro_result returned from napi_gro_receive to determine
193*5113495bSYour Name  * is extra GRO flush still necessary.
194*5113495bSYour Name  */
195*5113495bSYour Name #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0))
196*5113495bSYour Name #define DP_IS_EXTRA_GRO_FLUSH_NECESSARY(_gro_ret) true
197*5113495bSYour Name #define GRO_DROP_UPDATE_STATUS(gro_ret, status)
198*5113495bSYour Name #else
199*5113495bSYour Name #define GRO_DROP_UPDATE_STATUS(gro_ret, status) \
200*5113495bSYour Name 	if ((gro_ret) == GRO_DROP) ((status) = QDF_STATUS_E_GRO_DROP)
201*5113495bSYour Name #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0))
202*5113495bSYour Name #define DP_IS_EXTRA_GRO_FLUSH_NECESSARY(_gro_ret) \
203*5113495bSYour Name 	((_gro_ret) != GRO_DROP)
204*5113495bSYour Name #else
205*5113495bSYour Name #define DP_IS_EXTRA_GRO_FLUSH_NECESSARY(_gro_ret) \
206*5113495bSYour Name 	((_gro_ret) != GRO_DROP && (_gro_ret) != GRO_NORMAL)
207*5113495bSYour Name #endif
208*5113495bSYour Name #endif
209*5113495bSYour Name 
210*5113495bSYour Name #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0))
211*5113495bSYour Name /**
212*5113495bSYour Name  * osif_dp_rx_thread_napi_gro_flush() - do gro flush
213*5113495bSYour Name  * @napi: napi used to do gro flush
214*5113495bSYour Name  * @flush_code: flush_code differentiating low_tput_flush and normal_flush
215*5113495bSYour Name  *
216*5113495bSYour Name  * if there is RX GRO_NORMAL packets pending in napi
217*5113495bSYour Name  * rx_list, flush them manually right after napi_gro_flush.
218*5113495bSYour Name  *
219*5113495bSYour Name  * Return: none
220*5113495bSYour Name  */
221*5113495bSYour Name static inline
osif_dp_rx_thread_napi_gro_flush(struct napi_struct * napi,enum dp_rx_gro_flush_code flush_code)222*5113495bSYour Name void osif_dp_rx_thread_napi_gro_flush(struct napi_struct *napi,
223*5113495bSYour Name 				      enum dp_rx_gro_flush_code flush_code)
224*5113495bSYour Name {
225*5113495bSYour Name 	if (napi->poll) {
226*5113495bSYour Name 		/* Skipping GRO flush in low TPUT */
227*5113495bSYour Name 		if (flush_code != DP_RX_GRO_LOW_TPUT_FLUSH)
228*5113495bSYour Name 			napi_gro_flush(napi, false);
229*5113495bSYour Name 
230*5113495bSYour Name 		if (napi->rx_count) {
231*5113495bSYour Name 			netif_receive_skb_list(&napi->rx_list);
232*5113495bSYour Name 			qdf_init_list_head(&napi->rx_list);
233*5113495bSYour Name 			napi->rx_count = 0;
234*5113495bSYour Name 		}
235*5113495bSYour Name 	}
236*5113495bSYour Name }
237*5113495bSYour Name #else
238*5113495bSYour Name static inline
osif_dp_rx_thread_napi_gro_flush(struct napi_struct * napi,enum dp_rx_gro_flush_code flush_code)239*5113495bSYour Name void osif_dp_rx_thread_napi_gro_flush(struct napi_struct *napi,
240*5113495bSYour Name 				      enum dp_rx_gro_flush_code flush_code)
241*5113495bSYour Name {
242*5113495bSYour Name 	if (napi->poll) {
243*5113495bSYour Name 		/* Skipping GRO flush in low TPUT */
244*5113495bSYour Name 		if (flush_code != DP_RX_GRO_LOW_TPUT_FLUSH)
245*5113495bSYour Name 			napi_gro_flush(napi, false);
246*5113495bSYour Name 	}
247*5113495bSYour Name }
248*5113495bSYour Name #endif
249*5113495bSYour Name 
250*5113495bSYour Name /**
251*5113495bSYour Name  * osif_dp_rx_napi_gro_flush() - GRO RX/flush function.
252*5113495bSYour Name  * @napi_to_use: napi to be used to give packets to the stack, gro flush
253*5113495bSYour Name  * @nbuf: pointer to n/w buff
254*5113495bSYour Name  * @low_tput_force_flush: Is force flush required in low tput
255*5113495bSYour Name  *
256*5113495bSYour Name  * Function calls napi_gro_receive for the skb. If the skb indicates that a
257*5113495bSYour Name  * flush needs to be done (set by the lower DP layer), the function also calls
258*5113495bSYour Name  * napi_gro_flush. Local softirqs are disabled (and later enabled) while making
259*5113495bSYour Name  * napi_gro__ calls.
260*5113495bSYour Name  *
261*5113495bSYour Name  * Return: QDF_STATUS_SUCCESS if not dropped by napi_gro_receive or
262*5113495bSYour Name  *	   QDF error code.
263*5113495bSYour Name  */
264*5113495bSYour Name 
265*5113495bSYour Name static QDF_STATUS
osif_dp_rx_napi_gro_flush(qdf_napi_struct * napi_to_use,qdf_nbuf_t nbuf,uint8_t * low_tput_force_flush)266*5113495bSYour Name osif_dp_rx_napi_gro_flush(qdf_napi_struct *napi_to_use,
267*5113495bSYour Name 			  qdf_nbuf_t nbuf,
268*5113495bSYour Name 			  uint8_t *low_tput_force_flush)
269*5113495bSYour Name {
270*5113495bSYour Name 	QDF_STATUS status = QDF_STATUS_SUCCESS;
271*5113495bSYour Name 	gro_result_t gro_ret;
272*5113495bSYour Name 
273*5113495bSYour Name 	skb_set_hash(nbuf, QDF_NBUF_CB_RX_FLOW_ID(nbuf), PKT_HASH_TYPE_L4);
274*5113495bSYour Name 
275*5113495bSYour Name 	local_bh_disable();
276*5113495bSYour Name 	gro_ret = napi_gro_receive((struct napi_struct *)napi_to_use, nbuf);
277*5113495bSYour Name 
278*5113495bSYour Name 	if (DP_IS_EXTRA_GRO_FLUSH_NECESSARY(gro_ret)) {
279*5113495bSYour Name 		*low_tput_force_flush = 1;
280*5113495bSYour Name 		osif_dp_rx_thread_napi_gro_flush((struct napi_struct *)napi_to_use,
281*5113495bSYour Name 						 DP_RX_GRO_NORMAL_FLUSH);
282*5113495bSYour Name 	}
283*5113495bSYour Name 
284*5113495bSYour Name 	local_bh_enable();
285*5113495bSYour Name 	GRO_DROP_UPDATE_STATUS(gro_ret, status);
286*5113495bSYour Name 
287*5113495bSYour Name 	return status;
288*5113495bSYour Name }
289*5113495bSYour Name 
290*5113495bSYour Name /**
291*5113495bSYour Name  * osif_dp_rx_napi_gro_receive() - GRO RX receive function.
292*5113495bSYour Name  * @napi_to_use: napi to be used to give packets to the stack
293*5113495bSYour Name  * @nbuf: pointer to n/w buff
294*5113495bSYour Name  *
295*5113495bSYour Name  * Function calls napi_gro_receive for the skb.
296*5113495bSYour Name  * napi_gro_flush. Local softirqs are disabled (and later enabled) while making
297*5113495bSYour Name  * napi_gro__ calls.
298*5113495bSYour Name  *
299*5113495bSYour Name  * Return: QDF_STATUS_SUCCESS if not dropped by napi_gro_receive or
300*5113495bSYour Name  *	   QDF error code.
301*5113495bSYour Name  */
302*5113495bSYour Name static QDF_STATUS
osif_dp_rx_napi_gro_receive(qdf_napi_struct * napi_to_use,qdf_nbuf_t nbuf)303*5113495bSYour Name osif_dp_rx_napi_gro_receive(qdf_napi_struct *napi_to_use,
304*5113495bSYour Name 			    qdf_nbuf_t nbuf)
305*5113495bSYour Name {
306*5113495bSYour Name 	QDF_STATUS status = QDF_STATUS_SUCCESS;
307*5113495bSYour Name 	gro_result_t gro_ret;
308*5113495bSYour Name 
309*5113495bSYour Name 	skb_set_hash(nbuf, QDF_NBUF_CB_RX_FLOW_ID(nbuf), PKT_HASH_TYPE_L4);
310*5113495bSYour Name 
311*5113495bSYour Name 	local_bh_disable();
312*5113495bSYour Name 	gro_ret = napi_gro_receive((struct napi_struct *)napi_to_use, nbuf);
313*5113495bSYour Name 
314*5113495bSYour Name 	local_bh_enable();
315*5113495bSYour Name 	GRO_DROP_UPDATE_STATUS(gro_ret, status);
316*5113495bSYour Name 
317*5113495bSYour Name 	return status;
318*5113495bSYour Name }
319*5113495bSYour Name 
320*5113495bSYour Name #ifdef RECEIVE_OFFLOAD
321*5113495bSYour Name /**
322*5113495bSYour Name  * osif_dp_rxthread_napi_normal_gro_flush() - GRO flush cbk for NAPI+Rx_Thread
323*5113495bSYour Name  * Rx mode
324*5113495bSYour Name  * @data: hif NAPI context
325*5113495bSYour Name  *
326*5113495bSYour Name  * Return: none
327*5113495bSYour Name  */
osif_dp_rxthread_napi_normal_gro_flush(void * data)328*5113495bSYour Name static void osif_dp_rxthread_napi_normal_gro_flush(void *data)
329*5113495bSYour Name {
330*5113495bSYour Name 	struct qca_napi_info *qca_napi = (struct qca_napi_info *)data;
331*5113495bSYour Name 
332*5113495bSYour Name 	local_bh_disable();
333*5113495bSYour Name 	/*
334*5113495bSYour Name 	 * As we are breaking context in Rxthread mode, there is rx_thread NAPI
335*5113495bSYour Name 	 * corresponds each hif_napi.
336*5113495bSYour Name 	 */
337*5113495bSYour Name 	osif_dp_rx_thread_napi_gro_flush(&qca_napi->rx_thread_napi,
338*5113495bSYour Name 					 DP_RX_GRO_NORMAL_FLUSH);
339*5113495bSYour Name 	local_bh_enable();
340*5113495bSYour Name }
341*5113495bSYour Name 
342*5113495bSYour Name /**
343*5113495bSYour Name  * osif_dp_hif_napi_gro_flush() - GRO flush callback for NAPI Rx mode
344*5113495bSYour Name  * @data: hif NAPI context
345*5113495bSYour Name  *
346*5113495bSYour Name  * Return: none
347*5113495bSYour Name  */
osif_dp_hif_napi_gro_flush(void * data)348*5113495bSYour Name static void osif_dp_hif_napi_gro_flush(void *data)
349*5113495bSYour Name {
350*5113495bSYour Name 	struct qca_napi_info *qca_napi = (struct qca_napi_info *)data;
351*5113495bSYour Name 
352*5113495bSYour Name 	local_bh_disable();
353*5113495bSYour Name 	napi_gro_flush(&qca_napi->napi, false);
354*5113495bSYour Name 	local_bh_enable();
355*5113495bSYour Name }
356*5113495bSYour Name #endif
357*5113495bSYour Name 
358*5113495bSYour Name #ifdef FEATURE_LRO
359*5113495bSYour Name /**
360*5113495bSYour Name  * osif_dp_qdf_lro_flush() - LRO flush wrapper
361*5113495bSYour Name  * @data: hif NAPI context
362*5113495bSYour Name  *
363*5113495bSYour Name  * Return: none
364*5113495bSYour Name  */
osif_dp_qdf_lro_flush(void * data)365*5113495bSYour Name static void osif_dp_qdf_lro_flush(void *data)
366*5113495bSYour Name {
367*5113495bSYour Name 	struct qca_napi_info *qca_napii = (struct qca_napi_info *)data;
368*5113495bSYour Name 	qdf_lro_ctx_t qdf_lro_ctx = qca_napii->lro_ctx;
369*5113495bSYour Name 
370*5113495bSYour Name 	qdf_lro_flush(qdf_lro_ctx);
371*5113495bSYour Name }
372*5113495bSYour Name #elif defined(RECEIVE_OFFLOAD)
osif_dp_qdf_lro_flush(void * data)373*5113495bSYour Name static void osif_dp_qdf_lro_flush(void *data)
374*5113495bSYour Name {
375*5113495bSYour Name }
376*5113495bSYour Name #endif
377*5113495bSYour Name 
378*5113495bSYour Name #ifdef WLAN_FEATURE_DYNAMIC_RX_AGGREGATION
379*5113495bSYour Name #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0))
380*5113495bSYour Name static enum qdisc_filter_status
__osif_check_for_prio_filter_in_clsact_qdisc(struct tcf_block * block,uint32_t prio)381*5113495bSYour Name __osif_check_for_prio_filter_in_clsact_qdisc(struct tcf_block *block,
382*5113495bSYour Name 					     uint32_t prio)
383*5113495bSYour Name {
384*5113495bSYour Name 	struct tcf_chain *chain;
385*5113495bSYour Name 	struct tcf_proto *tp;
386*5113495bSYour Name 	struct tcf_proto *tp_next;
387*5113495bSYour Name 	enum qdisc_filter_status ret = QDISC_FILTER_PRIO_MISMATCH;
388*5113495bSYour Name 
389*5113495bSYour Name 	mutex_lock(&block->lock);
390*5113495bSYour Name 	list_for_each_entry(chain, &block->chain_list, list) {
391*5113495bSYour Name 		mutex_lock(&chain->filter_chain_lock);
392*5113495bSYour Name 		tp = tcf_chain_dereference(chain->filter_chain, chain);
393*5113495bSYour Name 		while (tp) {
394*5113495bSYour Name 			tp_next = rtnl_dereference(tp->next);
395*5113495bSYour Name 			if (tp->prio == (prio << 16)) {
396*5113495bSYour Name 				ret = QDISC_FILTER_PRIO_MATCH;
397*5113495bSYour Name 				break;
398*5113495bSYour Name 			}
399*5113495bSYour Name 			tp = tp_next;
400*5113495bSYour Name 		}
401*5113495bSYour Name 		mutex_unlock(&chain->filter_chain_lock);
402*5113495bSYour Name 
403*5113495bSYour Name 		if (ret == QDISC_FILTER_PRIO_MATCH)
404*5113495bSYour Name 			break;
405*5113495bSYour Name 	}
406*5113495bSYour Name 	mutex_unlock(&block->lock);
407*5113495bSYour Name 
408*5113495bSYour Name 	return ret;
409*5113495bSYour Name }
410*5113495bSYour Name #else
411*5113495bSYour Name static enum qdisc_filter_status
__osif_check_for_prio_filter_in_clsact_qdisc(struct tcf_block * block,uint32_t prio)412*5113495bSYour Name __osif_check_for_prio_filter_in_clsact_qdisc(struct tcf_block *block,
413*5113495bSYour Name 					     uint32_t prio)
414*5113495bSYour Name {
415*5113495bSYour Name 	struct tcf_chain *chain;
416*5113495bSYour Name 	struct tcf_proto *tp;
417*5113495bSYour Name 	enum qdisc_filter_status ret = QDISC_FILTER_PRIO_MISMATCH;
418*5113495bSYour Name 
419*5113495bSYour Name 	if (!rtnl_trylock())
420*5113495bSYour Name 		return QDISC_FILTER_RTNL_LOCK_FAIL;
421*5113495bSYour Name 
422*5113495bSYour Name 	list_for_each_entry(chain, &block->chain_list, list) {
423*5113495bSYour Name 		for (tp = rtnl_dereference(chain->filter_chain); tp;
424*5113495bSYour Name 		     tp = rtnl_dereference(tp->next)) {
425*5113495bSYour Name 			if (tp->prio == (prio << 16))
426*5113495bSYour Name 				ret = QDISC_FILTER_PRIO_MATCH;
427*5113495bSYour Name 		}
428*5113495bSYour Name 	}
429*5113495bSYour Name 	rtnl_unlock();
430*5113495bSYour Name 
431*5113495bSYour Name 	return ret;
432*5113495bSYour Name }
433*5113495bSYour Name #endif
434*5113495bSYour Name 
435*5113495bSYour Name /**
436*5113495bSYour Name  * osif_check_for_prio_filter_in_clsact_qdisc() - Check if priority 3 filter
437*5113495bSYour Name  *  is configured in the ingress clsact qdisc
438*5113495bSYour Name  * @qdisc: pointer to clsact qdisc
439*5113495bSYour Name  * @prio: traffic priority
440*5113495bSYour Name  *
441*5113495bSYour Name  * Return: qdisc filter status
442*5113495bSYour Name  */
443*5113495bSYour Name static enum qdisc_filter_status
osif_check_for_prio_filter_in_clsact_qdisc(struct Qdisc * qdisc,uint32_t prio)444*5113495bSYour Name osif_check_for_prio_filter_in_clsact_qdisc(struct Qdisc *qdisc, uint32_t prio)
445*5113495bSYour Name {
446*5113495bSYour Name 	const struct Qdisc_class_ops *cops;
447*5113495bSYour Name 	struct tcf_block *ingress_block;
448*5113495bSYour Name 
449*5113495bSYour Name 	cops = qdisc->ops->cl_ops;
450*5113495bSYour Name 	if (qdf_unlikely(!cops || !cops->tcf_block))
451*5113495bSYour Name 		return QDISC_FILTER_PRIO_MISMATCH;
452*5113495bSYour Name 
453*5113495bSYour Name 	ingress_block = cops->tcf_block(qdisc, TC_H_MIN_INGRESS, NULL);
454*5113495bSYour Name 	if (qdf_unlikely(!ingress_block))
455*5113495bSYour Name 		return QDISC_FILTER_PRIO_MISMATCH;
456*5113495bSYour Name 
457*5113495bSYour Name 	return __osif_check_for_prio_filter_in_clsact_qdisc(ingress_block,
458*5113495bSYour Name 							    prio);
459*5113495bSYour Name }
460*5113495bSYour Name 
461*5113495bSYour Name /**
462*5113495bSYour Name  * osif_dp_rx_check_qdisc_configured() - Check if any ingress qdisc
463*5113495bSYour Name  * configured for given netdev
464*5113495bSYour Name  * @ndev: pointer to netdev
465*5113495bSYour Name  * @prio: traffic priority
466*5113495bSYour Name  *
467*5113495bSYour Name  * The function checks if ingress qdisc is registered for a given
468*5113495bSYour Name  * net device.
469*5113495bSYour Name  *
470*5113495bSYour Name  * Return: None
471*5113495bSYour Name  */
472*5113495bSYour Name static QDF_STATUS
osif_dp_rx_check_qdisc_configured(qdf_netdev_t ndev,uint32_t prio)473*5113495bSYour Name osif_dp_rx_check_qdisc_configured(qdf_netdev_t ndev, uint32_t prio)
474*5113495bSYour Name {
475*5113495bSYour Name 	struct netdev_queue *ingress_q;
476*5113495bSYour Name 	struct Qdisc *ingress_qdisc;
477*5113495bSYour Name 	struct net_device *dev = (struct net_device *)ndev;
478*5113495bSYour Name 	bool disable_gro = false;
479*5113495bSYour Name 	enum qdisc_filter_status status;
480*5113495bSYour Name 
481*5113495bSYour Name 	if (!dev->ingress_queue)
482*5113495bSYour Name 		goto reset_wl;
483*5113495bSYour Name 
484*5113495bSYour Name 	if (!rtnl_trylock())
485*5113495bSYour Name 		return QDF_STATUS_E_AGAIN;
486*5113495bSYour Name 
487*5113495bSYour Name 	ingress_q = rtnl_dereference(dev->ingress_queue);
488*5113495bSYour Name 	if (qdf_unlikely(!ingress_q))
489*5113495bSYour Name 		goto reset;
490*5113495bSYour Name 
491*5113495bSYour Name 	ingress_qdisc = rtnl_dereference(ingress_q->qdisc);
492*5113495bSYour Name 	if (qdf_unlikely(!ingress_qdisc))
493*5113495bSYour Name 		goto reset;
494*5113495bSYour Name 
495*5113495bSYour Name 	if (qdf_str_eq(ingress_qdisc->ops->id, "ingress")) {
496*5113495bSYour Name 		disable_gro = true;
497*5113495bSYour Name 	} else if (qdf_str_eq(ingress_qdisc->ops->id, "clsact")) {
498*5113495bSYour Name 		status = osif_check_for_prio_filter_in_clsact_qdisc(
499*5113495bSYour Name 								  ingress_qdisc,
500*5113495bSYour Name 								  prio);
501*5113495bSYour Name 
502*5113495bSYour Name 		if (status == QDISC_FILTER_PRIO_MISMATCH)
503*5113495bSYour Name 			goto reset;
504*5113495bSYour Name 
505*5113495bSYour Name 		disable_gro = true;
506*5113495bSYour Name 	}
507*5113495bSYour Name 
508*5113495bSYour Name 	if (disable_gro) {
509*5113495bSYour Name 		rtnl_unlock();
510*5113495bSYour Name 		return QDF_STATUS_SUCCESS;
511*5113495bSYour Name 	}
512*5113495bSYour Name 
513*5113495bSYour Name reset:
514*5113495bSYour Name 	rtnl_unlock();
515*5113495bSYour Name 
516*5113495bSYour Name reset_wl:
517*5113495bSYour Name 	return QDF_STATUS_E_NOSUPPORT;
518*5113495bSYour Name }
519*5113495bSYour Name 
520*5113495bSYour Name #else
521*5113495bSYour Name static QDF_STATUS
osif_dp_rx_check_qdisc_configured(qdf_netdev_t ndev,uint32_t prio)522*5113495bSYour Name osif_dp_rx_check_qdisc_configured(qdf_netdev_t ndev, uint32_t prio)
523*5113495bSYour Name {
524*5113495bSYour Name 	return QDF_STATUS_E_NOSUPPORT;
525*5113495bSYour Name }
526*5113495bSYour Name #endif
527*5113495bSYour Name 
528*5113495bSYour Name #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0))
529*5113495bSYour Name static void
osif_dp_register_arp_unsolicited_cbk(struct wlan_dp_psoc_callbacks * cb_obj)530*5113495bSYour Name osif_dp_register_arp_unsolicited_cbk(struct wlan_dp_psoc_callbacks *cb_obj)
531*5113495bSYour Name {
532*5113495bSYour Name 	cb_obj->dp_is_gratuitous_arp_unsolicited_na = NULL;
533*5113495bSYour Name }
534*5113495bSYour Name #else
osif_dp_is_gratuitous_arp_unsolicited_na(qdf_nbuf_t nbuf)535*5113495bSYour Name static bool osif_dp_is_gratuitous_arp_unsolicited_na(qdf_nbuf_t nbuf)
536*5113495bSYour Name {
537*5113495bSYour Name 	return cfg80211_is_gratuitous_arp_unsolicited_na((struct sk_buff *)nbuf);
538*5113495bSYour Name }
539*5113495bSYour Name 
540*5113495bSYour Name static void
osif_dp_register_arp_unsolicited_cbk(struct wlan_dp_psoc_callbacks * cb_obj)541*5113495bSYour Name osif_dp_register_arp_unsolicited_cbk(struct wlan_dp_psoc_callbacks *cb_obj)
542*5113495bSYour Name {
543*5113495bSYour Name 	cb_obj->dp_is_gratuitous_arp_unsolicited_na =
544*5113495bSYour Name 		osif_dp_is_gratuitous_arp_unsolicited_na;
545*5113495bSYour Name }
546*5113495bSYour Name #endif
547*5113495bSYour Name 
548*5113495bSYour Name #if defined(CFG80211_CTRL_FRAME_SRC_ADDR_TA_ADDR)
549*5113495bSYour Name #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 41))
550*5113495bSYour Name static
osif_dp_cfg80211_rx_control_port(qdf_netdev_t dev,u8 * ta_addr,qdf_nbuf_t nbuf,bool unencrypted)551*5113495bSYour Name bool osif_dp_cfg80211_rx_control_port(qdf_netdev_t dev, u8 *ta_addr,
552*5113495bSYour Name 				      qdf_nbuf_t nbuf, bool unencrypted)
553*5113495bSYour Name {
554*5113495bSYour Name 	return cfg80211_rx_control_port((struct net_device *)dev,
555*5113495bSYour Name 					(struct sk_buff *)nbuf,
556*5113495bSYour Name 					unencrypted, -1);
557*5113495bSYour Name }
558*5113495bSYour Name 
559*5113495bSYour Name #else
560*5113495bSYour Name static
osif_dp_cfg80211_rx_control_port(qdf_netdev_t dev,u8 * ta_addr,qdf_nbuf_t nbuf,bool unencrypted)561*5113495bSYour Name bool osif_dp_cfg80211_rx_control_port(qdf_netdev_t dev, u8 *ta_addr,
562*5113495bSYour Name 				      qdf_nbuf_t nbuf, bool unencrypted)
563*5113495bSYour Name {
564*5113495bSYour Name 	return cfg80211_rx_control_port((struct net_device *)dev,
565*5113495bSYour Name 					ta_addr, (struct sk_buff *)nbuf,
566*5113495bSYour Name 					unencrypted);
567*5113495bSYour Name }
568*5113495bSYour Name #endif
569*5113495bSYour Name 
570*5113495bSYour Name static void
osif_dp_register_send_rx_pkt_over_nl(struct wlan_dp_psoc_callbacks * cb_obj)571*5113495bSYour Name osif_dp_register_send_rx_pkt_over_nl(struct wlan_dp_psoc_callbacks *cb_obj)
572*5113495bSYour Name {
573*5113495bSYour Name 	cb_obj->dp_send_rx_pkt_over_nl = osif_dp_cfg80211_rx_control_port;
574*5113495bSYour Name }
575*5113495bSYour Name 
576*5113495bSYour Name #else
577*5113495bSYour Name static void
osif_dp_register_send_rx_pkt_over_nl(struct wlan_dp_psoc_callbacks * cb_obj)578*5113495bSYour Name osif_dp_register_send_rx_pkt_over_nl(struct wlan_dp_psoc_callbacks *cb_obj)
579*5113495bSYour Name {
580*5113495bSYour Name 	cb_obj->dp_send_rx_pkt_over_nl = NULL;
581*5113495bSYour Name }
582*5113495bSYour Name #endif
583*5113495bSYour Name 
584*5113495bSYour Name #ifdef RECEIVE_OFFLOAD
585*5113495bSYour Name static
osif_dp_register_rx_offld_flush_cb(enum dp_rx_offld_flush_cb cb_type)586*5113495bSYour Name void osif_dp_register_rx_offld_flush_cb(enum dp_rx_offld_flush_cb cb_type)
587*5113495bSYour Name {
588*5113495bSYour Name 	void *soc = cds_get_context(QDF_MODULE_ID_SOC);
589*5113495bSYour Name 
590*5113495bSYour Name 	if (cb_type == DP_RX_FLUSH_LRO)
591*5113495bSYour Name 		cdp_register_rx_offld_flush_cb(soc, osif_dp_qdf_lro_flush);
592*5113495bSYour Name 	else if (cb_type == DP_RX_FLUSH_THREAD)
593*5113495bSYour Name 		cdp_register_rx_offld_flush_cb(soc,
594*5113495bSYour Name 					       osif_dp_rxthread_napi_normal_gro_flush);
595*5113495bSYour Name 	else if (cb_type == DP_RX_FLUSH_NAPI)
596*5113495bSYour Name 		cdp_register_rx_offld_flush_cb(soc,
597*5113495bSYour Name 					       osif_dp_hif_napi_gro_flush);
598*5113495bSYour Name }
599*5113495bSYour Name #else
600*5113495bSYour Name 
601*5113495bSYour Name static
osif_dp_register_rx_offld_flush_cb(enum dp_rx_offld_flush_cb cb_type)602*5113495bSYour Name void osif_dp_register_rx_offld_flush_cb(enum dp_rx_offld_flush_cb cb_type) { }
603*5113495bSYour Name #endif
604*5113495bSYour Name 
605*5113495bSYour Name static
osif_dp_rx_pkt_to_nw(qdf_nbuf_t nbuf,enum dp_nbuf_push_type type)606*5113495bSYour Name QDF_STATUS osif_dp_rx_pkt_to_nw(qdf_nbuf_t nbuf, enum dp_nbuf_push_type type)
607*5113495bSYour Name {
608*5113495bSYour Name 	int netif_status;
609*5113495bSYour Name 
610*5113495bSYour Name 	if (type == DP_NBUF_PUSH_BH_DISABLE) {
611*5113495bSYour Name 		local_bh_disable();
612*5113495bSYour Name 		netif_status = netif_receive_skb(nbuf);
613*5113495bSYour Name 		local_bh_enable();
614*5113495bSYour Name 	} else if (type == DP_NBUF_PUSH_NI) {
615*5113495bSYour Name 		netif_status = netif_rx_ni(nbuf);
616*5113495bSYour Name 	} else if (type == DP_NBUF_PUSH_NAPI) {
617*5113495bSYour Name 		netif_status = netif_receive_skb(nbuf);
618*5113495bSYour Name 	} else {
619*5113495bSYour Name 		netif_status = netif_rx(nbuf);
620*5113495bSYour Name 	}
621*5113495bSYour Name 
622*5113495bSYour Name 	if (qdf_likely(netif_status == NET_RX_SUCCESS))
623*5113495bSYour Name 		return QDF_STATUS_SUCCESS;
624*5113495bSYour Name 
625*5113495bSYour Name 	return QDF_STATUS_E_FAILURE;
626*5113495bSYour Name }
627*5113495bSYour Name 
os_if_dp_register_txrx_callbacks(struct wlan_dp_psoc_callbacks * cb_obj)628*5113495bSYour Name void os_if_dp_register_txrx_callbacks(struct wlan_dp_psoc_callbacks *cb_obj)
629*5113495bSYour Name {
630*5113495bSYour Name 	cb_obj->dp_nbuf_push_pkt = osif_dp_rx_pkt_to_nw;
631*5113495bSYour Name 	cb_obj->dp_rx_napi_gro_flush = osif_dp_rx_napi_gro_flush;
632*5113495bSYour Name 	cb_obj->dp_rx_napi_gro_receive = osif_dp_rx_napi_gro_receive;
633*5113495bSYour Name 	cb_obj->dp_rx_thread_napi_gro_flush = osif_dp_rx_thread_napi_gro_flush;
634*5113495bSYour Name 	cb_obj->dp_lro_rx_cb = osif_dp_lro_rx;
635*5113495bSYour Name 	cb_obj->dp_register_rx_offld_flush_cb =
636*5113495bSYour Name 		osif_dp_register_rx_offld_flush_cb;
637*5113495bSYour Name 	cb_obj->dp_rx_check_qdisc_configured =
638*5113495bSYour Name 		osif_dp_rx_check_qdisc_configured;
639*5113495bSYour Name 
640*5113495bSYour Name 	osif_dp_register_arp_unsolicited_cbk(cb_obj);
641*5113495bSYour Name 
642*5113495bSYour Name 	osif_dp_register_send_rx_pkt_over_nl(cb_obj);
643*5113495bSYour Name }
644