1  /*
2   * Copyright (c) 2013-2021 The Linux Foundation. All rights reserved.
3   * Copyright (c) 2021-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  /**
21   * DOC: wlan_hdd_ipa.c
22   *
23   * WLAN HDD and ipa interface implementation
24   */
25  
26  /* Include Files */
27  #include <wlan_hdd_includes.h>
28  #include <wlan_hdd_ipa.h>
29  #include "wlan_policy_mgr_ucfg.h"
30  #include "wlan_ipa_ucfg_api.h"
31  #include <wlan_hdd_softap_tx_rx.h>
32  #include <linux/inetdevice.h>
33  #include <qdf_trace.h>
34  /* Test against msm kernel version */
35  #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)) && \
36  	IS_ENABLED(CONFIG_SCHED_WALT)
37  #include <linux/sched/walt.h>
38  #endif
39  #include "wlan_hdd_object_manager.h"
40  #include "wlan_dp_ucfg_api.h"
41  
42  #ifdef IPA_OFFLOAD
43  
44  /**
45   * struct hdd_ipa_connection_info - connectio info for IPA component
46   * @vdev_id: vdev id
47   * @ch_freq: channel frequency
48   * @ch_width: channel width
49   * @wlan_80211_mode: enum qca_wlan_802_11_mode
50   */
51  struct hdd_ipa_connection_info {
52  	uint8_t vdev_id;
53  	qdf_freq_t ch_freq;
54  	enum phy_ch_width ch_width;
55  	enum qca_wlan_802_11_mode wlan_80211_mode;
56  };
57  
58  #if (defined(QCA_CONFIG_SMP) && defined(PF_WAKE_UP_IDLE)) ||\
59  	IS_ENABLED(CONFIG_SCHED_WALT)
60  /**
61   * hdd_ipa_get_wake_up_idle() - Get PF_WAKE_UP_IDLE flag in the task structure
62   *
63   * Get PF_WAKE_UP_IDLE flag in the task structure
64   *
65   * Return: 1 if PF_WAKE_UP_IDLE flag is set, 0 otherwise
66   */
hdd_ipa_get_wake_up_idle(void)67  static uint32_t hdd_ipa_get_wake_up_idle(void)
68  {
69  	return sched_get_wake_up_idle(current);
70  }
71  
72  /**
73   * hdd_ipa_set_wake_up_idle() - Set PF_WAKE_UP_IDLE flag in the task structure
74   * @wake_up_idle: Value to set PF_WAKE_UP_IDLE flag
75   *
76   * Set PF_WAKE_UP_IDLE flag in the task structure
77   * This task and any task woken by this will be waken to idle CPU
78   *
79   * Return: None
80   */
hdd_ipa_set_wake_up_idle(bool wake_up_idle)81  static void hdd_ipa_set_wake_up_idle(bool wake_up_idle)
82  {
83  	sched_set_wake_up_idle(current, wake_up_idle);
84  }
85  #else
hdd_ipa_get_wake_up_idle(void)86  static uint32_t hdd_ipa_get_wake_up_idle(void)
87  {
88  	return 0;
89  }
90  
hdd_ipa_set_wake_up_idle(bool wake_up_idle)91  static void hdd_ipa_set_wake_up_idle(bool wake_up_idle)
92  {
93  }
94  #endif
95  
96  #ifdef QCA_CONFIG_SMP
97  /**
98   * hdd_ipa_send_to_nw_stack() - Check if IPA supports NAPI
99   * polling during RX
100   * @skb : data buffer sent to network stack
101   *
102   * If IPA LAN RX supports NAPI polling mechanism use
103   * netif_receive_skb instead of netif_rx_ni to forward the skb
104   * to network stack.
105   *
106   * Return: Return value from netif_rx_ni/netif_receive_skb
107   */
hdd_ipa_send_to_nw_stack(qdf_nbuf_t skb)108  static int hdd_ipa_send_to_nw_stack(qdf_nbuf_t skb)
109  {
110  	int result;
111  
112  	if (qdf_ipa_get_lan_rx_napi())
113  		result = netif_receive_skb(skb);
114  	else
115  		result = netif_rx_ni(skb);
116  	return result;
117  }
118  #else
hdd_ipa_send_to_nw_stack(qdf_nbuf_t skb)119  static int hdd_ipa_send_to_nw_stack(qdf_nbuf_t skb)
120  {
121  	int result;
122  
123  	result = netif_rx_ni(skb);
124  	return result;
125  }
126  #endif
127  
128  #ifdef QCA_CONFIG_SMP
129  
130  /**
131   * hdd_ipa_aggregated_rx_ind() - Submit aggregated packets to the stack
132   * @skb: skb to be submitted to the stack
133   *
134   * For CONFIG_SMP systems, simply call netif_rx_ni.
135   * For non CONFIG_SMP systems call netif_rx till
136   * IPA_WLAN_RX_SOFTIRQ_THRESH. When threshold is reached call netif_rx_ni.
137   * In this manner, UDP/TCP packets are sent in an aggregated way to the stack.
138   * For IP/ICMP packets, simply call netif_rx_ni.
139   *
140   * Check if IPA supports NAPI polling then use netif_receive_skb
141   * instead of netif_rx_ni.
142   *
143   * Return: return value from the netif_rx_ni/netif_rx api.
144   */
hdd_ipa_aggregated_rx_ind(qdf_nbuf_t skb)145  static int hdd_ipa_aggregated_rx_ind(qdf_nbuf_t skb)
146  {
147  	int ret;
148  
149  	ret =  hdd_ipa_send_to_nw_stack(skb);
150  	return ret;
151  }
152  #else
hdd_ipa_aggregated_rx_ind(qdf_nbuf_t skb)153  static int hdd_ipa_aggregated_rx_ind(qdf_nbuf_t skb)
154  {
155  	struct iphdr *ip_h;
156  	static atomic_t softirq_mitigation_cntr =
157  		ATOMIC_INIT(IPA_WLAN_RX_SOFTIRQ_THRESH);
158  	int result;
159  
160  	ip_h = (struct iphdr *)(skb->data);
161  	if ((skb->protocol == htons(ETH_P_IP)) &&
162  		(ip_h->protocol == IPPROTO_ICMP)) {
163  		result = hdd_ipa_send_to_nw_stack(skb);
164  	} else {
165  		/* Call netif_rx_ni for every IPA_WLAN_RX_SOFTIRQ_THRESH packets
166  		 * to avoid excessive softirq's.
167  		 */
168  		if (atomic_dec_and_test(&softirq_mitigation_cntr)) {
169  			result = hdd_ipa_send_to_nw_stack(skb);
170  			atomic_set(&softirq_mitigation_cntr,
171  					IPA_WLAN_RX_SOFTIRQ_THRESH);
172  		} else {
173  			result = netif_rx(skb);
174  		}
175  	}
176  
177  	return result;
178  }
179  #endif
180  
hdd_ipa_send_nbuf_to_network(qdf_nbuf_t nbuf,qdf_netdev_t dev)181  void hdd_ipa_send_nbuf_to_network(qdf_nbuf_t nbuf, qdf_netdev_t dev)
182  {
183  	struct hdd_adapter *adapter = (struct hdd_adapter *) netdev_priv(dev);
184  	struct wlan_objmgr_vdev *vdev;
185  	int result;
186  	bool delivered = false;
187  	uint32_t enabled, len = 0;
188  	struct hdd_tx_rx_stats *stats;
189  	struct hdd_station_ctx *sta_ctx;
190  	bool is_eapol;
191  	u8 *ta_addr = NULL;
192  
193  	if (hdd_validate_adapter(adapter)) {
194  		kfree_skb(nbuf);
195  		return;
196  	}
197  
198  	if (cds_is_driver_unloading()) {
199  		kfree_skb(nbuf);
200  		return;
201  	}
202  
203  	stats = &adapter->deflink->hdd_stats.tx_rx_stats;
204  	hdd_ipa_update_rx_mcbc_stats(adapter, nbuf);
205  
206  	if ((adapter->device_mode == QDF_SAP_MODE) &&
207  	    (qdf_nbuf_is_ipv4_dhcp_pkt(nbuf) == true)) {
208  		/* Send DHCP Indication to FW */
209  		vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink,
210  						   WLAN_DP_ID);
211  		if (vdev) {
212  			ucfg_dp_softap_inspect_dhcp_packet(vdev, nbuf, QDF_RX);
213  			hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID);
214  		}
215  	}
216  
217  	is_eapol = qdf_nbuf_is_ipv4_eapol_pkt(nbuf);
218  
219  	qdf_dp_trace_set_track(nbuf, QDF_RX);
220  
221  	ucfg_dp_event_eapol_log(nbuf, QDF_RX);
222  	qdf_dp_trace_log_pkt(adapter->deflink->vdev_id,
223  			     nbuf, QDF_RX, QDF_TRACE_DEFAULT_PDEV_ID,
224  			     adapter->device_mode);
225  	DPTRACE(qdf_dp_trace(nbuf,
226  			     QDF_DP_TRACE_RX_HDD_PACKET_PTR_RECORD,
227  			     QDF_TRACE_DEFAULT_PDEV_ID,
228  			     qdf_nbuf_data_addr(nbuf),
229  			     sizeof(qdf_nbuf_data(nbuf)), QDF_RX));
230  	DPTRACE(qdf_dp_trace_data_pkt(nbuf, QDF_TRACE_DEFAULT_PDEV_ID,
231  				      QDF_DP_TRACE_RX_PACKET_RECORD, 0,
232  				      QDF_RX));
233  
234  	/*
235  	 * Set PF_WAKE_UP_IDLE flag in the task structure
236  	 * This task and any task woken by this will be waken to idle CPU
237  	 */
238  	enabled = hdd_ipa_get_wake_up_idle();
239  	if (!enabled)
240  		hdd_ipa_set_wake_up_idle(true);
241  
242  	nbuf->dev = adapter->dev;
243  	nbuf->protocol = eth_type_trans(nbuf, nbuf->dev);
244  	nbuf->ip_summed = CHECKSUM_NONE;
245  	len = nbuf->len;
246  
247  	/*
248  	 * Update STA RX exception packet stats.
249  	 * For SAP as part of IPA HW stats are updated.
250  	 */
251  
252  	if (is_eapol && SEND_EAPOL_OVER_NL) {
253  		if (adapter->device_mode == QDF_SAP_MODE) {
254  			ta_addr = adapter->mac_addr.bytes;
255  		} else if (adapter->device_mode == QDF_STA_MODE) {
256  			sta_ctx =
257  				WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink);
258  			ta_addr = (u8 *)&sta_ctx->conn_info.peer_macaddr;
259  		}
260  
261  		if (ta_addr) {
262  			if (wlan_hdd_cfg80211_rx_control_port(adapter->dev,
263  							      ta_addr, nbuf,
264  							      false))
265  				result = NET_RX_SUCCESS;
266  			else
267  				result = NET_RX_DROP;
268  		} else {
269  			result = NET_RX_DROP;
270  		}
271  
272  		dev_kfree_skb(nbuf);
273  	} else {
274  		result = hdd_ipa_aggregated_rx_ind(nbuf);
275  	}
276  
277  	if (result == NET_RX_SUCCESS)
278  		delivered = true;
279  	/*
280  	 * adapter->vdev is directly dereferenced because this is per packet
281  	 * path, hdd_get_vdev_by_user() usage will be very costly as it involves
282  	 * lock access.
283  	 * Expectation here is vdev will be present during TX/RX processing
284  	 * and also DP internally maintaining vdev ref count
285  	 */
286  	ucfg_dp_inc_rx_pkt_stats(adapter->deflink->vdev,
287  				 len, delivered);
288  	/*
289  	 * Restore PF_WAKE_UP_IDLE flag in the task structure
290  	 */
291  	if (!enabled)
292  		hdd_ipa_set_wake_up_idle(false);
293  }
294  
hdd_ipa_set_mcc_mode(bool mcc_mode)295  void hdd_ipa_set_mcc_mode(bool mcc_mode)
296  {
297  	struct hdd_context *hdd_ctx;
298  
299  	hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
300  	if (!hdd_ctx)
301  		return;
302  
303  	ucfg_ipa_set_mcc_mode(hdd_ctx->pdev, mcc_mode);
304  }
305  
306  #ifdef IPA_WDI3_TX_TWO_PIPES
307  static void
hdd_ipa_fill_sta_connection_info(struct wlan_hdd_link_info * link,struct hdd_ipa_connection_info * conn)308  hdd_ipa_fill_sta_connection_info(struct wlan_hdd_link_info *link,
309  				 struct hdd_ipa_connection_info *conn)
310  {
311  	struct hdd_station_ctx *ctx = WLAN_HDD_GET_STATION_CTX_PTR(link);
312  
313  	conn->ch_freq = ctx->conn_info.chan_freq;
314  	conn->ch_width = ctx->conn_info.ch_width;
315  	conn->wlan_80211_mode = hdd_convert_cfgdot11mode_to_80211mode(
316  			ctx->conn_info.dot11mode);
317  }
318  
319  static void
hdd_ipa_fill_sap_connection_info(struct wlan_hdd_link_info * link,struct hdd_ipa_connection_info * conn)320  hdd_ipa_fill_sap_connection_info(struct wlan_hdd_link_info *link,
321  				 struct hdd_ipa_connection_info *conn)
322  {
323  	struct hdd_ap_ctx *ctx = WLAN_HDD_GET_AP_CTX_PTR(link);
324  
325  	conn->ch_freq = ctx->operating_chan_freq;
326  	conn->ch_width = ctx->sap_config.ch_params.ch_width;
327  	conn->wlan_80211_mode = hdd_convert_phymode_to_80211mode(
328  			ctx->sap_config.SapHw_mode);
329  }
330  
hdd_ipa_fill_connection_info(struct wlan_hdd_link_info * link,struct hdd_ipa_connection_info * conn)331  static void hdd_ipa_fill_connection_info(struct wlan_hdd_link_info *link,
332  					 struct hdd_ipa_connection_info *conn)
333  {
334  	struct hdd_adapter *adapter = link->adapter;
335  
336  	conn->vdev_id = link->vdev_id;
337  
338  	if (adapter->device_mode == QDF_STA_MODE)
339  		hdd_ipa_fill_sta_connection_info(link, conn);
340  	else if (adapter->device_mode == QDF_SAP_MODE)
341  		hdd_ipa_fill_sap_connection_info(link, conn);
342  }
343  
344  static QDF_STATUS
hdd_ipa_get_tx_pipe_multi_conn(struct hdd_context * hdd_ctx,struct hdd_ipa_connection_info * conn,bool * tx_pipe)345  hdd_ipa_get_tx_pipe_multi_conn(struct hdd_context *hdd_ctx,
346  			       struct hdd_ipa_connection_info *conn,
347  			       bool *tx_pipe)
348  {
349  	uint32_t new_freq = conn->ch_freq;
350  	QDF_STATUS status;
351  	uint8_t vdev_id;
352  	bool pipe;
353  
354  	if (ucfg_policy_mgr_get_vdev_same_freq_new_conn(hdd_ctx->psoc,
355  							new_freq,
356  							&vdev_id)) {
357  		/* Inherit the pipe selection of the connection that has
358  		 * same freq.
359  		 */
360  		return ucfg_ipa_get_alt_pipe(hdd_ctx->pdev, vdev_id, tx_pipe);
361  	} else {
362  		if (ucfg_policy_mgr_get_vdev_diff_freq_new_conn(hdd_ctx->psoc,
363  								new_freq,
364  								&vdev_id)) {
365  			status = ucfg_ipa_get_alt_pipe(hdd_ctx->pdev, vdev_id,
366  						       &pipe);
367  			if (QDF_IS_STATUS_ERROR(status))
368  				return QDF_STATUS_E_INVAL;
369  
370  			/* Inverse the pipe selection of the connection that
371  			 * has different channel frequency.
372  			 */
373  			*tx_pipe = !pipe;
374  			return QDF_STATUS_SUCCESS;
375  		} else {
376  			return QDF_STATUS_E_INVAL;
377  		}
378  	}
379  }
380  
hdd_ipa_get_tx_pipe(struct hdd_context * hdd_ctx,struct wlan_hdd_link_info * link,bool * tx_pipe)381  QDF_STATUS hdd_ipa_get_tx_pipe(struct hdd_context *hdd_ctx,
382  			       struct wlan_hdd_link_info *link,
383  			       bool *tx_pipe)
384  {
385  	struct hdd_ipa_connection_info conn;
386  	uint32_t count;
387  
388  	if (qdf_unlikely(!hdd_ctx || !link || !tx_pipe)) {
389  		hdd_debug("Invalid parameters");
390  		return QDF_STATUS_E_INVAL;
391  	}
392  
393  	/* If SBS not capable, use legacy DBS selection */
394  	if (!ucfg_policy_mgr_is_hw_sbs_capable(hdd_ctx->psoc)) {
395  		hdd_debug("firmware is not sbs capable");
396  		*tx_pipe = WLAN_REG_IS_24GHZ_CH_FREQ(conn.ch_freq);
397  		return QDF_STATUS_SUCCESS;
398  	}
399  
400  	hdd_ipa_fill_connection_info(link, &conn);
401  
402  	/* Always select the primary pipe for connection that is EHT160 or
403  	 * EHT320 due to higher tput requiements.
404  	 */
405  	if (conn.wlan_80211_mode == QCA_WLAN_802_11_MODE_11BE &&
406  	    (conn.ch_width == CH_WIDTH_160MHZ ||
407  	     conn.ch_width == CH_WIDTH_320MHZ)) {
408  		*tx_pipe = false;
409  		return QDF_STATUS_SUCCESS;
410  	}
411  
412  	count = ucfg_policy_mgr_get_connection_count(hdd_ctx->psoc);
413  	if (!count) {
414  		/* For first connection that is below EHT160, select the
415  		 * alternate pipe so as to reserve the primary pipe for
416  		 * potential connections that are above EHT160.
417  		 */
418  		*tx_pipe = true;
419  		return QDF_STATUS_SUCCESS;
420  	}
421  
422  	return hdd_ipa_get_tx_pipe_multi_conn(hdd_ctx, &conn, tx_pipe);
423  }
424  #else /* !IPA_WDI3_TX_TWO_PIPES */
hdd_ipa_get_tx_pipe(struct hdd_context * hdd_ctx,struct wlan_hdd_link_info * link,bool * tx_pipe)425  QDF_STATUS hdd_ipa_get_tx_pipe(struct hdd_context *hdd_ctx,
426  			       struct wlan_hdd_link_info *link,
427  			       bool *tx_pipe)
428  {
429  	if (qdf_unlikely(!tx_pipe))
430  		return QDF_STATUS_E_INVAL;
431  
432  	/* For IPA_WDI3_TX_TWO_PIPES=n, only one tx pipe is available */
433  	*tx_pipe = false;
434  
435  	return QDF_STATUS_SUCCESS;
436  }
437  #endif /* IPA_WDI3_TX_TWO_PIPES */
438  
hdd_ipa_set_perf_level_bw(enum hw_mode_bandwidth bw)439  void hdd_ipa_set_perf_level_bw(enum hw_mode_bandwidth bw)
440  {
441  	struct hdd_context *hdd_ctx;
442  	enum wlan_ipa_bw_level lvl;
443  
444  	hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
445  	if (!hdd_ctx)
446  		return;
447  
448  	if (bw == HW_MODE_320_MHZ)
449  		lvl = WLAN_IPA_BW_LEVEL_HIGH;
450  	else if (bw == HW_MODE_160_MHZ)
451  		lvl = WLAN_IPA_BW_LEVEL_MEDIUM;
452  	else
453  		lvl = WLAN_IPA_BW_LEVEL_LOW;
454  
455  	hdd_debug("Vote IPA perf level to %d", lvl);
456  	ucfg_ipa_set_perf_level_bw(hdd_ctx->pdev, lvl);
457  }
458  
459  #endif
460