1 /*
2  * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
3  * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #ifndef _WLAN_DP_SWLM_H_
19 #define _WLAN_DP_SWLM_H_
20 
21 #ifdef WLAN_DP_FEATURE_SW_LATENCY_MGR
22 
23 #define DP_SWLM_TCL_TPUT_PASS_THRESH 3
24 
25 #define DP_SWLM_TCL_RX_TRAFFIC_THRESH	50
26 #define DP_SWLM_TCL_TX_TRAFFIC_THRESH	50
27 #define DP_SWLM_TCL_TX_PKT_THRESH	2
28 
29 /* Traffic test time is in us */
30 #define DP_SWLM_TCL_TRAFFIC_SAMPLING_TIME 250
31 #define DP_SWLM_TCL_TIME_FLUSH_THRESH 1000
32 #define DP_SWLM_TCL_TX_THRESH_MULTIPLIER 2
33 
34 /* Inline Functions */
35 
36 /**
37  * dp_tx_is_special_frame() - check if this TX frame is a special frame.
38  * @nbuf: TX skb pointer
39  * @frame_mask: the mask for required special frames
40  *
41  * Check if TX frame is a required special frame.
42  *
43  * Returns: true, if this frame is a needed special frame,
44  *	    false, otherwise
45  */
46 static inline
dp_tx_is_special_frame(qdf_nbuf_t nbuf,uint32_t frame_mask)47 bool dp_tx_is_special_frame(qdf_nbuf_t nbuf, uint32_t frame_mask)
48 {
49 	if (((frame_mask & FRAME_MASK_IPV4_ARP) &&
50 	     qdf_nbuf_is_ipv4_arp_pkt(nbuf)) ||
51 	    ((frame_mask & FRAME_MASK_IPV4_DHCP) &&
52 	     qdf_nbuf_is_ipv4_dhcp_pkt(nbuf)) ||
53 	    ((frame_mask & FRAME_MASK_IPV4_EAPOL) &&
54 	     qdf_nbuf_is_ipv4_eapol_pkt(nbuf)) ||
55 	    ((frame_mask & FRAME_MASK_IPV6_DHCP) &&
56 	     qdf_nbuf_is_ipv6_dhcp_pkt(nbuf)))
57 		return true;
58 
59 	return false;
60 }
61 
62 /**
63  * dp_swlm_tcl_reset_session_data() -  Reset the TCL coalescing session data
64  * @soc: DP soc handle
65  * @ring_id: TCL ring id
66  *
67  * Returns QDF_STATUS
68  */
69 static inline QDF_STATUS
dp_swlm_tcl_reset_session_data(struct dp_soc * soc,uint8_t ring_id)70 dp_swlm_tcl_reset_session_data(struct dp_soc *soc, uint8_t ring_id)
71 {
72 	struct dp_swlm_params *params = &soc->swlm.params;
73 
74 	params->tcl[ring_id].coalesce_end_time = qdf_get_log_timestamp_usecs() +
75 		params->time_flush_thresh;
76 	params->tcl[ring_id].bytes_coalesced = 0;
77 	params->tcl[ring_id].bytes_flush_thresh =
78 				params->tcl[ring_id].sampling_session_tx_bytes *
79 				params->tx_thresh_multiplier;
80 	qdf_timer_sync_cancel(&params->tcl[ring_id].flush_timer);
81 
82 	return QDF_STATUS_SUCCESS;
83 }
84 
85 /**
86  * dp_swlm_tcl_pre_check() - Pre checks for current packet to be transmitted
87  * @soc: Datapath soc handle
88  * @tcl_data: tcl swlm data
89  *
90  * Returns: QDF_STATUS_SUCCESS, if all pre-check conditions pass
91  *	    QDF_STATUS_E_FAILURE, otherwise
92  */
93 static inline QDF_STATUS
dp_swlm_tcl_pre_check(struct dp_soc * soc,struct dp_swlm_tcl_data * tcl_data)94 dp_swlm_tcl_pre_check(struct dp_soc *soc,
95 		      struct dp_swlm_tcl_data *tcl_data)
96 {
97 	struct dp_swlm *swlm = &soc->swlm;
98 	uint32_t frame_mask = FRAME_MASK_IPV4_ARP | FRAME_MASK_IPV4_DHCP |
99 				FRAME_MASK_IPV4_EAPOL | FRAME_MASK_IPV6_DHCP;
100 
101 	if (tcl_data->tid > DP_VO_TID) {
102 		DP_STATS_INC(swlm, tcl[tcl_data->ring_id].tid_fail, 1);
103 		goto fail;
104 	}
105 
106 	if (dp_tx_is_special_frame(tcl_data->nbuf, frame_mask)) {
107 		DP_STATS_INC(swlm, tcl[tcl_data->ring_id].sp_frames, 1);
108 		goto fail;
109 	}
110 
111 	if (tcl_data->num_ll_connections) {
112 		DP_STATS_INC(swlm, tcl[tcl_data->ring_id].ll_connection, 1);
113 		goto fail;
114 	}
115 
116 	return QDF_STATUS_SUCCESS;
117 
118 fail:
119 	return QDF_STATUS_E_FAILURE;
120 }
121 
122 /**
123  * dp_swlm_query_policy() - apply software latency policy based on ring type.
124  * @soc: Datapath global soc handle
125  * @ring_type: SRNG type
126  * @query_data: private data for the query corresponding to the ring type
127  *
128  * Returns: 1, if policy is to be applied
129  *	    0, if policy is not to be applied
130  */
dp_swlm_query_policy(struct dp_soc * soc,int ring_type,union swlm_data query_data)131 static inline int dp_swlm_query_policy(struct dp_soc *soc, int ring_type,
132 				       union swlm_data query_data)
133 {
134 	struct dp_swlm *swlm = &soc->swlm;
135 
136 	switch (ring_type) {
137 	case TCL_DATA:
138 		return swlm->ops->tcl_wr_coalesce_check(soc,
139 							query_data.tcl_data);
140 	default:
141 		dp_err("Ring type %d not supported by SW latency manager",
142 		       ring_type);
143 		break;
144 	}
145 
146 	return 0;
147 }
148 
149 /* Function Declarations */
150 
151 /**
152  * dp_soc_swlm_attach() - attach the software latency manager resources
153  * @soc: Datapath global soc handle
154  *
155  * Returns: QDF_STATUS
156  */
157 QDF_STATUS dp_soc_swlm_attach(struct dp_soc *soc);
158 
159 /**
160  * dp_soc_swlm_detach() - detach the software latency manager resources
161  * @soc: Datapath global soc handle
162  *
163  * Returns: QDF_STATUS
164  */
165 QDF_STATUS dp_soc_swlm_detach(struct dp_soc *soc);
166 
167 /**
168  * dp_print_swlm_stats() - Print the SWLM stats
169  * @soc: Datapath soc handle
170  *
171  * Returns: QDF_STATUS
172  */
173 QDF_STATUS dp_print_swlm_stats(struct dp_soc *soc);
174 
175 #endif /* WLAN_DP_FEATURE_SW_LATENCY_MGR */
176 
177 #endif
178