1  /*
2   * Copyright (c) 2017-2019 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
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  #include "dp_cal_client_api.h"
21  #include "qdf_module.h"
22  
23  /* dp_cal_client_attach - function to attach cal client timer
24   * @cal_client_ctx: cal client timer context
25   * @pdev: pdev handle
26   * @osdev: device pointer
27   * @dp_iterate_peer_list : function pointer to iterate and update peer stats
28   *
29   * return: void
30   */
dp_cal_client_attach(struct cdp_cal_client ** cal_client_ctx,struct cdp_pdev * pdev,qdf_device_t osdev,void (* dp_iterate_peer_list)(struct cdp_pdev *))31  void dp_cal_client_attach(struct cdp_cal_client **cal_client_ctx,
32  			  struct cdp_pdev *pdev,
33  			  qdf_device_t osdev,
34  			  void (*dp_iterate_peer_list)(struct cdp_pdev *))
35  {
36  	struct cal_client *cal_cl;
37  
38  	*cal_client_ctx = qdf_mem_malloc(sizeof(struct cal_client));
39  
40  	if (!(*cal_client_ctx))
41  		return;
42  
43  	cal_cl = (struct cal_client *)(*cal_client_ctx);
44  	cal_cl->iterate_update_peer_list = dp_iterate_peer_list;
45  	cal_cl->pdev_hdl = pdev;
46  
47  	qdf_timer_init(osdev, &cal_cl->cal_client_timer,
48  		       dp_cal_client_stats_timer_fn, *cal_client_ctx,
49  		       QDF_TIMER_TYPE_WAKE_APPS);
50  }
51  
52  qdf_export_symbol(dp_cal_client_attach);
53  
54  /* dp_cal_client_detach - detach cal client timer
55   * @cal_client_ctx: cal client timer context
56   *
57   * return: void
58   */
dp_cal_client_detach(struct cdp_cal_client ** cal_client_ctx)59  void dp_cal_client_detach(struct cdp_cal_client **cal_client_ctx)
60  {
61  	struct cal_client *cal_cl;
62  
63  	if (*cal_client_ctx) {
64  		cal_cl = (struct cal_client *)*cal_client_ctx;
65  
66  		qdf_timer_stop(&cal_cl->cal_client_timer);
67  		qdf_timer_free(&cal_cl->cal_client_timer);
68  		qdf_mem_free(cal_cl);
69  		*cal_client_ctx = NULL;
70  	}
71  }
72  
73  qdf_export_symbol(dp_cal_client_detach);
74  
75  /* dp_cal_client_timer_start- api to start cal client timer
76   * @ctx: cal client timer ctx
77   *
78   * return: void
79   */
dp_cal_client_timer_start(void * ctx)80  void dp_cal_client_timer_start(void *ctx)
81  {
82  	struct cal_client *cal_cl;
83  
84  	if (ctx) {
85  		cal_cl  = (struct cal_client *)ctx;
86  		qdf_timer_start(&cal_cl->cal_client_timer, DP_CAL_CLIENT_TIME);
87  	}
88  }
89  
90  qdf_export_symbol(dp_cal_client_timer_start);
91  
92  /* dp_cal_client_timer_stop- api to stop cal client timer
93   * @ctx: cal client timer ctx
94   *
95   * return: void
96   */
dp_cal_client_timer_stop(void * ctx)97  void dp_cal_client_timer_stop(void *ctx)
98  {
99  	struct cal_client *cal_cl;
100  
101  	if (ctx) {
102  		cal_cl = (struct cal_client *)ctx;
103  		qdf_timer_sync_cancel(&cal_cl->cal_client_timer);
104  		qdf_timer_stop(&cal_cl->cal_client_timer);
105  	}
106  }
107  
108  qdf_export_symbol(dp_cal_client_timer_stop);
109  
110  /* dp_cal_client_stats_timer_fn- function called on timer interval
111   * @ctx: cal client timer ctx
112   *
113   * return: void
114   */
dp_cal_client_stats_timer_fn(void * ctx)115  void dp_cal_client_stats_timer_fn(void *ctx)
116  {
117  	struct cal_client *cal_cl = (struct cal_client *)ctx;
118  
119  	if (!cal_cl)
120  		return;
121  
122  	cal_cl->iterate_update_peer_list(cal_cl->pdev_hdl);
123  	qdf_timer_mod(&cal_cl->cal_client_timer, DP_CAL_CLIENT_TIME);
124  }
125  
126  qdf_export_symbol(dp_cal_client_stats_timer_fn);
127  
128  /*dp_cal_client_update_peer_stats - update peer stats in peer
129   * @peer_stats: cdp peer stats pointer
130   *
131   * return: void
132   */
dp_cal_client_update_peer_stats(struct cdp_peer_stats * peer_stats)133  void dp_cal_client_update_peer_stats(struct cdp_peer_stats *peer_stats)
134  {
135  	uint32_t temp_rx_bytes = peer_stats->rx.to_stack.bytes;
136  	uint32_t temp_rx_data = peer_stats->rx.to_stack.num;
137  	uint32_t temp_tx_bytes = peer_stats->tx.tx_success.bytes;
138  	uint32_t temp_tx_data = peer_stats->tx.tx_success.num;
139  	uint32_t temp_tx_ucast_pkts = peer_stats->tx.ucast.num;
140  
141  	peer_stats->rx.rx_byte_rate = temp_rx_bytes -
142  					peer_stats->rx.rx_bytes_success_last;
143  	peer_stats->rx.rx_data_rate  = temp_rx_data -
144  					peer_stats->rx.rx_data_success_last;
145  	peer_stats->tx.tx_byte_rate = temp_tx_bytes -
146  					peer_stats->tx.tx_bytes_success_last;
147  	peer_stats->tx.tx_data_rate  = temp_tx_data -
148  					peer_stats->tx.tx_data_success_last;
149  	peer_stats->tx.tx_data_ucast_rate = temp_tx_ucast_pkts -
150  					peer_stats->tx.tx_data_ucast_last;
151  
152  	/* Check tx and rx packets in last one second, and increment
153  	 * inactive time for peer
154  	 */
155  	if (peer_stats->tx.tx_data_rate || peer_stats->rx.rx_data_rate)
156  		peer_stats->tx.inactive_time = 0;
157  	else
158  		peer_stats->tx.inactive_time++;
159  
160  	peer_stats->rx.rx_bytes_success_last = temp_rx_bytes;
161  	peer_stats->rx.rx_data_success_last = temp_rx_data;
162  	peer_stats->tx.tx_bytes_success_last = temp_tx_bytes;
163  	peer_stats->tx.tx_data_success_last = temp_tx_data;
164  	peer_stats->tx.tx_data_ucast_last = temp_tx_ucast_pkts;
165  
166  	if (peer_stats->tx.tx_data_ucast_rate) {
167  		if (peer_stats->tx.tx_data_ucast_rate >
168  				peer_stats->tx.tx_data_rate)
169  			peer_stats->tx.last_per =
170  				((peer_stats->tx.tx_data_ucast_rate -
171  					peer_stats->tx.tx_data_rate) * 100) /
172  				peer_stats->tx.tx_data_ucast_rate;
173  		else
174  			peer_stats->tx.last_per = 0;
175  	}
176  
177  }
178  
179  qdf_export_symbol(dp_cal_client_update_peer_stats);
180  
dp_cal_client_update_peer_stats_wifi3(struct cdp_calibr_stats_intf * peer_stats_intf,struct cdp_calibr_stats * peer_calibr_stats)181  void dp_cal_client_update_peer_stats_wifi3(struct cdp_calibr_stats_intf *peer_stats_intf,
182  					   struct cdp_calibr_stats *peer_calibr_stats)
183  {
184  	uint32_t temp_rx_bytes = peer_stats_intf->to_stack.bytes;
185  	uint32_t temp_rx_data = peer_stats_intf->to_stack.num;
186  	uint32_t temp_tx_bytes = peer_stats_intf->tx_success.bytes;
187  	uint32_t temp_tx_data = peer_stats_intf->tx_success.num;
188  	uint32_t temp_tx_ucast_pkts = peer_stats_intf->tx_ucast.num;
189  
190  	peer_calibr_stats->rx.rx_byte_rate = temp_rx_bytes -
191  				peer_calibr_stats->rx.rx_bytes_success_last;
192  	peer_calibr_stats->rx.rx_data_rate  = temp_rx_data -
193  				peer_calibr_stats->rx.rx_data_success_last;
194  	peer_calibr_stats->tx.tx_byte_rate = temp_tx_bytes -
195  				peer_calibr_stats->tx.tx_bytes_success_last;
196  	peer_calibr_stats->tx.tx_data_rate  = temp_tx_data -
197  				peer_calibr_stats->tx.tx_data_success_last;
198  	peer_calibr_stats->tx.tx_data_ucast_rate = temp_tx_ucast_pkts -
199  				peer_calibr_stats->tx.tx_data_ucast_last;
200  
201  	/* Check tx and rx packets in last one second, and increment
202  	 * inactive time for peer
203  	 */
204  	if (peer_calibr_stats->tx.tx_data_rate || peer_calibr_stats->rx.rx_data_rate)
205  		peer_calibr_stats->tx.inactive_time = 0;
206  	else
207  		peer_calibr_stats->tx.inactive_time++;
208  
209  	peer_calibr_stats->rx.rx_bytes_success_last = temp_rx_bytes;
210  	peer_calibr_stats->rx.rx_data_success_last = temp_rx_data;
211  	peer_calibr_stats->tx.tx_bytes_success_last = temp_tx_bytes;
212  	peer_calibr_stats->tx.tx_data_success_last = temp_tx_data;
213  	peer_calibr_stats->tx.tx_data_ucast_last = temp_tx_ucast_pkts;
214  
215  	if (peer_calibr_stats->tx.tx_data_ucast_rate) {
216  		if (peer_calibr_stats->tx.tx_data_ucast_rate >
217  				peer_calibr_stats->tx.tx_data_rate)
218  			peer_calibr_stats->tx.last_per =
219  				((peer_calibr_stats->tx.tx_data_ucast_rate -
220  					peer_calibr_stats->tx.tx_data_rate) * 100) /
221  				peer_calibr_stats->tx.tx_data_ucast_rate;
222  		else
223  			peer_calibr_stats->tx.last_per = 0;
224  	}
225  }
226  
227  qdf_export_symbol(dp_cal_client_update_peer_stats_wifi3);
228