blob: 5c4d503489a5a088f65887066ea211d829bbe340 [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
Orhan K AKYILDIZ4f20db52015-12-30 12:35:44 -08002 * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/*
23 * This file was originally distributed by Qualcomm Atheros, Inc.
24 * under proprietary terms before Copyright ownership was assigned
25 * to the Linux Foundation.
26 */
27
28/**
29 * DOC: wlan_hdd_tx_rx.c
30 *
31 * Linux HDD Tx/RX APIs
32 */
33
34#include <wlan_hdd_tx_rx.h>
35#include <wlan_hdd_softap_tx_rx.h>
36#include <wlan_hdd_napi.h>
37#include <linux/netdevice.h>
38#include <linux/skbuff.h>
39#include <linux/etherdevice.h>
40#include <cds_sched.h>
41
42#include <wlan_hdd_p2p.h>
43#include <linux/wireless.h>
44#include <net/cfg80211.h>
45#include <net/ieee80211_radiotap.h>
46#include "sap_api.h"
47#include "wlan_hdd_wmm.h"
48
49#ifdef FEATURE_WLAN_TDLS
50#include "wlan_hdd_tdls.h"
51#endif
52#include <wlan_hdd_ipa.h>
53
54#include "wlan_hdd_ocb.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080055#include "wlan_hdd_lro.h"
56
Dhanashri Atreb08959a2016-03-01 17:28:03 -080057#include "cdp_txrx_peer_ops.h"
Manjunathappa Prakash59f861d2016-04-21 10:33:31 -070058#include "ol_txrx.h"
Dhanashri Atreb08959a2016-03-01 17:28:03 -080059
Deepak Dhamdhere5872c8c2016-06-02 15:51:47 -070060#include "wlan_hdd_nan_datapath.h"
61
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080062const uint8_t hdd_wmm_ac_to_highest_up[] = {
63 SME_QOS_WMM_UP_RESV,
64 SME_QOS_WMM_UP_EE,
65 SME_QOS_WMM_UP_VI,
66 SME_QOS_WMM_UP_NC
67};
68
69/* Mapping Linux AC interpretation to SME AC. */
70const uint8_t hdd_qdisc_ac_to_tl_ac[] = {
71 SME_AC_VO,
72 SME_AC_VI,
73 SME_AC_BE,
74 SME_AC_BK,
75};
76
77#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
78/**
79 * hdd_tx_resume_timer_expired_handler() - TX Q resume timer handler
80 * @adapter_context: pointer to vdev adapter
81 *
82 * If Blocked OS Q is not resumed during timeout period, to prevent
83 * permanent stall, resume OS Q forcefully.
84 *
85 * Return: None
86 */
87void hdd_tx_resume_timer_expired_handler(void *adapter_context)
88{
89 hdd_adapter_t *pAdapter = (hdd_adapter_t *) adapter_context;
90
91 if (!pAdapter) {
92 /* INVALID ARG */
93 return;
94 }
95
96 hddLog(LOG1, FL("Enabling queues"));
97 wlan_hdd_netif_queue_control(pAdapter, WLAN_WAKE_ALL_NETIF_QUEUE,
98 WLAN_CONTROL_PATH);
99 return;
100}
Poddar, Siddarthb61cf642016-04-28 16:02:39 +0530101#if defined(CONFIG_PER_VDEV_TX_DESC_POOL)
102
103/**
104 * hdd_tx_resume_false() - Resume OS TX Q false leads to queue disabling
105 * @pAdapter: pointer to hdd adapter
106 * @tx_resume: TX Q resume trigger
107 *
108 *
109 * Return: None
110 */
111static void
112hdd_tx_resume_false(hdd_adapter_t *pAdapter, bool tx_resume)
113{
114 if (true == tx_resume)
115 return;
116
117 /* Pause TX */
118 hdd_notice("Disabling queues");
119 wlan_hdd_netif_queue_control(pAdapter, WLAN_STOP_ALL_NETIF_QUEUE,
120 WLAN_DATA_FLOW_CONTROL);
121
122 if (QDF_TIMER_STATE_STOPPED ==
123 qdf_mc_timer_get_current_state(&pAdapter->
124 tx_flow_control_timer)) {
125 QDF_STATUS status;
126 status = qdf_mc_timer_start(&pAdapter->tx_flow_control_timer,
127 WLAN_HDD_TX_FLOW_CONTROL_OS_Q_BLOCK_TIME);
128
129 if (!QDF_IS_STATUS_SUCCESS(status))
130 hdd_err("Failed to start tx_flow_control_timer");
131 else
132 pAdapter->hdd_stats.hddTxRxStats.txflow_timer_cnt++;
133 }
134
135 pAdapter->hdd_stats.hddTxRxStats.txflow_pause_cnt++;
136 pAdapter->hdd_stats.hddTxRxStats.is_txflow_paused = true;
137
138 return;
139}
140#else
141
142static inline void
143hdd_tx_resume_false(hdd_adapter_t *pAdapter, bool tx_resume)
144{
145 return;
146}
147#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800148
149/**
150 * hdd_tx_resume_cb() - Resume OS TX Q.
151 * @adapter_context: pointer to vdev apdapter
152 * @tx_resume: TX Q resume trigger
153 *
154 * Q was stopped due to WLAN TX path low resource condition
155 *
156 * Return: None
157 */
158void hdd_tx_resume_cb(void *adapter_context, bool tx_resume)
159{
160 hdd_adapter_t *pAdapter = (hdd_adapter_t *) adapter_context;
161 hdd_station_ctx_t *hdd_sta_ctx = NULL;
162
163 if (!pAdapter) {
164 /* INVALID ARG */
165 return;
166 }
167
168 hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
169
170 /* Resume TX */
171 if (true == tx_resume) {
Anurag Chouhan210db072016-02-22 18:42:15 +0530172 if (QDF_TIMER_STATE_STOPPED !=
173 qdf_mc_timer_get_current_state(&pAdapter->
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800174 tx_flow_control_timer)) {
Anurag Chouhan210db072016-02-22 18:42:15 +0530175 qdf_mc_timer_stop(&pAdapter->tx_flow_control_timer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800176 }
Anurag Chouhanc5548422016-02-24 18:33:27 +0530177 if (qdf_unlikely(hdd_sta_ctx->hdd_ReassocScenario)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800178 hddLog(LOGW,
179 FL("flow control, tx queues un-pause avoided as we are in REASSOCIATING state"));
180 return;
181 }
182 hddLog(LOG1, FL("Enabling queues"));
183 wlan_hdd_netif_queue_control(pAdapter,
184 WLAN_WAKE_ALL_NETIF_QUEUE,
185 WLAN_DATA_FLOW_CONTROL);
186 }
Poddar, Siddarthb61cf642016-04-28 16:02:39 +0530187 hdd_tx_resume_false(pAdapter, tx_resume);
188
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800189 return;
190}
191
192/**
193 * hdd_register_tx_flow_control() - Register TX Flow control
194 * @adapter: adapter handle
195 * @timer_callback: timer callback
196 * @flow_control_fp: txrx flow control
197 *
198 * Return: none
199 */
200void hdd_register_tx_flow_control(hdd_adapter_t *adapter,
Anurag Chouhan210db072016-02-22 18:42:15 +0530201 qdf_mc_timer_callback_t timer_callback,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800202 ol_txrx_tx_flow_control_fp flow_control_fp)
203{
204 if (adapter->tx_flow_timer_initialized == false) {
Anurag Chouhan210db072016-02-22 18:42:15 +0530205 qdf_mc_timer_init(&adapter->tx_flow_control_timer,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530206 QDF_TIMER_TYPE_SW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800207 timer_callback,
208 adapter);
209 adapter->tx_flow_timer_initialized = true;
210 }
211 ol_txrx_register_tx_flow_control(adapter->sessionId,
212 flow_control_fp,
213 adapter);
214
215}
216
217/**
218 * hdd_deregister_tx_flow_control() - Deregister TX Flow control
219 * @adapter: adapter handle
220 *
221 * Return: none
222 */
223void hdd_deregister_tx_flow_control(hdd_adapter_t *adapter)
224{
225 ol_txrx_deregister_tx_flow_control_cb(adapter->sessionId);
226 if (adapter->tx_flow_timer_initialized == true) {
Anurag Chouhan210db072016-02-22 18:42:15 +0530227 qdf_mc_timer_stop(&adapter->tx_flow_control_timer);
228 qdf_mc_timer_destroy(&adapter->tx_flow_control_timer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800229 adapter->tx_flow_timer_initialized = false;
230 }
231}
232
233/**
234 * hdd_get_tx_resource() - check tx resources and take action
235 * @adapter: adapter handle
236 * @STAId: station id
237 * @timer_value: timer value
238 *
239 * Return: none
240 */
241void hdd_get_tx_resource(hdd_adapter_t *adapter,
242 uint8_t STAId, uint16_t timer_value)
243{
244 if (false ==
245 ol_txrx_get_tx_resource(STAId,
246 adapter->tx_flow_low_watermark,
247 adapter->tx_flow_high_watermark_offset)) {
248 hdd_info("Disabling queues lwm %d hwm offset %d",
249 adapter->tx_flow_low_watermark,
250 adapter->tx_flow_high_watermark_offset);
251 wlan_hdd_netif_queue_control(adapter, WLAN_STOP_ALL_NETIF_QUEUE,
252 WLAN_DATA_FLOW_CONTROL);
253 if ((adapter->tx_flow_timer_initialized == true) &&
Anurag Chouhan210db072016-02-22 18:42:15 +0530254 (QDF_TIMER_STATE_STOPPED ==
255 qdf_mc_timer_get_current_state(&adapter->
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800256 tx_flow_control_timer))) {
Anurag Chouhan210db072016-02-22 18:42:15 +0530257 qdf_mc_timer_start(&adapter->tx_flow_control_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800258 timer_value);
259 adapter->hdd_stats.hddTxRxStats.txflow_timer_cnt++;
260 adapter->hdd_stats.hddTxRxStats.txflow_pause_cnt++;
261 adapter->hdd_stats.hddTxRxStats.is_txflow_paused = true;
262 }
263 }
264}
265
266#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
267
Nirav Shah5e74bb82016-07-20 16:01:27 +0530268/**
269 * qdf_event_eapol_log() - send event to wlan diag
270 * @skb: skb ptr
271 * @dir: direction
272 * @eapol_key_info: eapol key info
273 *
274 * Return: None
275 */
276void hdd_event_eapol_log(struct sk_buff *skb, enum qdf_proto_dir dir)
277{
278 int16_t eapol_key_info;
279
280 WLAN_HOST_DIAG_EVENT_DEF(wlan_diag_event, struct host_event_wlan_eapol);
281
282 if ((dir == QDF_TX &&
283 (QDF_NBUF_CB_PACKET_TYPE_EAPOL !=
284 QDF_NBUF_CB_GET_PACKET_TYPE(skb))))
285 return;
286 else if (!qdf_nbuf_is_ipv4_eapol_pkt(skb))
287 return;
288
289 eapol_key_info = (uint16_t)(*(uint16_t *)
290 (skb->data + EAPOL_KEY_INFO_OFFSET));
291
292 wlan_diag_event.event_sub_type =
293 (dir == QDF_TX ?
294 WIFI_EVENT_DRIVER_EAPOL_FRAME_TRANSMIT_REQUESTED :
295 WIFI_EVENT_DRIVER_EAPOL_FRAME_RECEIVED);
296 wlan_diag_event.eapol_packet_type = (uint8_t)(*(uint8_t *)
297 (skb->data + EAPOL_PACKET_TYPE_OFFSET));
298 wlan_diag_event.eapol_key_info = eapol_key_info;
299 wlan_diag_event.eapol_rate = 0;
300 qdf_mem_copy(wlan_diag_event.dest_addr,
301 (skb->data + QDF_NBUF_DEST_MAC_OFFSET),
302 sizeof(wlan_diag_event.dest_addr));
303 qdf_mem_copy(wlan_diag_event.src_addr,
304 (skb->data + QDF_NBUF_SRC_MAC_OFFSET),
305 sizeof(wlan_diag_event.src_addr));
306
307 WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, EVENT_WLAN_EAPOL);
308}
309
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800310
311/**
Nirav Shah5e74bb82016-07-20 16:01:27 +0530312 * wlan_hdd_classify_pkt() - classify packet
313 * @skb - sk buff
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800314 *
Nirav Shah5e74bb82016-07-20 16:01:27 +0530315 * Return: none
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800316 */
Nirav Shah5e74bb82016-07-20 16:01:27 +0530317void wlan_hdd_classify_pkt(struct sk_buff *skb)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800318{
Nirav Shah5e74bb82016-07-20 16:01:27 +0530319 struct ethhdr *eh = (struct ethhdr *)skb->data;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800320
Nirav Shah5e74bb82016-07-20 16:01:27 +0530321 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800322
Nirav Shah5e74bb82016-07-20 16:01:27 +0530323 /* check destination mac address is broadcast/multicast */
324 if (is_broadcast_ether_addr((uint8_t *)eh))
325 QDF_NBUF_CB_GET_IS_BCAST(skb) = true;
326 else if (is_multicast_ether_addr((uint8_t *)eh))
327 QDF_NBUF_CB_GET_IS_MCAST(skb) = true;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800328
Nirav Shah5e74bb82016-07-20 16:01:27 +0530329 if (qdf_nbuf_is_ipv4_arp_pkt(skb))
330 QDF_NBUF_CB_GET_PACKET_TYPE(skb) =
331 QDF_NBUF_CB_PACKET_TYPE_ARP;
332 else if (qdf_nbuf_is_ipv4_dhcp_pkt(skb))
333 QDF_NBUF_CB_GET_PACKET_TYPE(skb) =
334 QDF_NBUF_CB_PACKET_TYPE_DHCP;
335 else if (qdf_nbuf_is_ipv4_eapol_pkt(skb))
336 QDF_NBUF_CB_GET_PACKET_TYPE(skb) =
337 QDF_NBUF_CB_PACKET_TYPE_EAPOL;
338 else if (qdf_nbuf_is_ipv4_wapi_pkt(skb))
339 QDF_NBUF_CB_GET_PACKET_TYPE(skb) =
340 QDF_NBUF_CB_PACKET_TYPE_WAPI;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800341
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800342}
343
344/**
Ravi Joshi24477b72016-07-19 15:45:09 -0700345 * hdd_get_transmit_sta_id() - function to retrieve station id to be used for
346 * sending traffic towards a particular destination address. The destination
347 * address can be unicast, multicast or broadcast
348 *
349 * @adapter: Handle to adapter context
350 * @dst_addr: Destination address
351 * @station_id: station id
352 *
353 * Returns: None
354 */
355static void hdd_get_transmit_sta_id(hdd_adapter_t *adapter,
Nirav Shah5e74bb82016-07-20 16:01:27 +0530356 struct sk_buff *skb, uint8_t *station_id)
Ravi Joshi24477b72016-07-19 15:45:09 -0700357{
358 bool mcbc_addr = false;
359 hdd_station_ctx_t *sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Nirav Shah5e74bb82016-07-20 16:01:27 +0530360 struct qdf_mac_addr *dst_addr = NULL;
Ravi Joshi24477b72016-07-19 15:45:09 -0700361
Nirav Shah5e74bb82016-07-20 16:01:27 +0530362 dst_addr = (struct qdf_mac_addr *)skb->data;
Ravi Joshi24477b72016-07-19 15:45:09 -0700363 hdd_get_peer_sta_id(sta_ctx, dst_addr, station_id);
364 if (*station_id == HDD_WLAN_INVALID_STA_ID) {
Nirav Shah5e74bb82016-07-20 16:01:27 +0530365 if (QDF_NBUF_CB_GET_IS_BCAST(skb) ||
366 QDF_NBUF_CB_GET_IS_MCAST(skb)) {
Ravi Joshi24477b72016-07-19 15:45:09 -0700367 hdd_info("Received MC/BC packet for transmission");
368 mcbc_addr = true;
Ravi Joshi24477b72016-07-19 15:45:09 -0700369 }
370 }
371
372 if (adapter->device_mode == QDF_IBSS_MODE) {
373 /*
374 * This check is necessary to make sure station id is not
375 * overwritten for UC traffic in IBSS mode
376 */
377 if (mcbc_addr)
378 *station_id = sta_ctx->broadcast_ibss_staid;
379 } else if (adapter->device_mode == QDF_NDI_MODE) {
380 /*
381 * This check is necessary to make sure station id is not
382 * overwritten for UC traffic in NAN data mode
383 */
384 if (mcbc_addr)
385 *station_id = NDP_BROADCAST_STAID;
386 } else {
387 /* For the rest, traffic is directed to AP/P2P GO */
388 if (eConnectionState_Associated == sta_ctx->conn_info.connState)
389 *station_id = sta_ctx->conn_info.staId[0];
390 }
391}
392
393/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800394 * hdd_hard_start_xmit() - Transmit a frame
395 * @skb: pointer to OS packet (sk_buff)
396 * @dev: pointer to network device
397 *
398 * Function registered with the Linux OS for transmitting
399 * packets. This version of the function directly passes
400 * the packet to Transport Layer.
401 *
402 * Return: Always returns NETDEV_TX_OK
403 */
404int hdd_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
405{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530406 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800407 sme_ac_enum_type ac;
408 sme_QosWmmUpType up;
409 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
410 bool granted;
Nirav Shah5e74bb82016-07-20 16:01:27 +0530411 uint8_t STAId;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800412 hdd_station_ctx_t *pHddStaCtx = &pAdapter->sessionCtx.station;
Kabilan Kannan36090ce2016-05-03 19:28:44 -0700413#ifdef QCA_PKT_PROTO_TRACE
414 uint8_t proto_type = 0;
415#endif /* QCA_PKT_PROTO_TRACE */
416 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(pAdapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800417
418#ifdef QCA_WIFI_FTM
Anurag Chouhan6d760662016-02-20 16:05:43 +0530419 if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800420 kfree_skb(skb);
421 return NETDEV_TX_OK;
422 }
423#endif
424
425 ++pAdapter->hdd_stats.hddTxRxStats.txXmitCalled;
Prashanth Bhatta9e143052015-12-04 11:56:47 -0800426 if (cds_is_driver_recovering()) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530427 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_WARN,
Prashanth Bhatta9e143052015-12-04 11:56:47 -0800428 "Recovery in progress, dropping the packet");
Nirav Shahdf3659e2016-06-27 12:26:28 +0530429 goto drop_pkt;
Govind Singhede435f2015-12-01 16:16:36 +0530430 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800431
Nirav Shah5e74bb82016-07-20 16:01:27 +0530432 wlan_hdd_classify_pkt(skb);
433
Ravi Joshi24477b72016-07-19 15:45:09 -0700434 STAId = HDD_WLAN_INVALID_STA_ID;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800435
Nirav Shah5e74bb82016-07-20 16:01:27 +0530436 hdd_get_transmit_sta_id(pAdapter, skb, &STAId);
Naveen Rawat209d0932016-08-03 15:07:23 -0700437 if (STAId >= WLAN_MAX_STA_COUNT) {
Ravi Joshi24477b72016-07-19 15:45:09 -0700438 hddLog(LOGE, "Invalid station id, transmit operation suspended");
439 goto drop_pkt;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800440 }
441
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800442 hdd_get_tx_resource(pAdapter, STAId,
443 WLAN_HDD_TX_FLOW_CONTROL_OS_Q_BLOCK_TIME);
444
445 /* Get TL AC corresponding to Qdisc queue index/AC. */
446 ac = hdd_qdisc_ac_to_tl_ac[skb->queue_mapping];
447
Nirav Shahcbc6d722016-03-01 16:24:53 +0530448 if (!qdf_nbuf_ipa_owned_get(skb)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800449 /* Check if the buffer has enough header room */
450 skb = skb_unshare(skb, GFP_ATOMIC);
451 if (!skb)
Nirav Shahdf3659e2016-06-27 12:26:28 +0530452 goto drop_pkt_accounting;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800453 }
454
Ravi Joshi24477b72016-07-19 15:45:09 -0700455 /*
456 * user priority from IP header, which is already extracted and set from
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800457 * select_queue call back function
458 */
459 up = skb->priority;
460
461 ++pAdapter->hdd_stats.hddTxRxStats.txXmitClassifiedAC[ac];
462#ifdef HDD_WMM_DEBUG
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530463 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_FATAL,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800464 "%s: Classified as ac %d up %d", __func__, ac, up);
465#endif /* HDD_WMM_DEBUG */
466
467 if (HDD_PSB_CHANGED == pAdapter->psbChanged) {
Ravi Joshi24477b72016-07-19 15:45:09 -0700468 /*
469 * Function which will determine acquire admittance for a
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800470 * WMM AC is required or not based on psb configuration done
471 * in the framework
472 */
473 hdd_wmm_acquire_access_required(pAdapter, ac);
474 }
475 /*
476 * Make sure we already have access to this access category
477 * or it is EAPOL or WAPI frame during initial authentication which
478 * can have artifically boosted higher qos priority.
479 */
480
481 if (((pAdapter->psbChanged & (1 << ac)) &&
482 likely(pAdapter->hddWmmStatus.wmmAcStatus[ac].
483 wmmAcAccessAllowed)) ||
484 ((pHddStaCtx->conn_info.uIsAuthenticated == false) &&
Nirav Shah5e74bb82016-07-20 16:01:27 +0530485 (QDF_NBUF_CB_PACKET_TYPE_EAPOL ==
486 QDF_NBUF_CB_GET_PACKET_TYPE(skb) ||
487 QDF_NBUF_CB_PACKET_TYPE_WAPI ==
488 QDF_NBUF_CB_GET_PACKET_TYPE(skb)))) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800489 granted = true;
490 } else {
491 status = hdd_wmm_acquire_access(pAdapter, ac, &granted);
492 pAdapter->psbChanged |= (1 << ac);
493 }
494
495 if (!granted) {
496 bool isDefaultAc = false;
Ravi Joshi24477b72016-07-19 15:45:09 -0700497 /*
498 * ADDTS request for this AC is sent, for now
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800499 * send this packet through next avaiable lower
500 * Access category until ADDTS negotiation completes.
501 */
502 while (!likely
503 (pAdapter->hddWmmStatus.wmmAcStatus[ac].
504 wmmAcAccessAllowed)) {
505 switch (ac) {
506 case SME_AC_VO:
507 ac = SME_AC_VI;
508 up = SME_QOS_WMM_UP_VI;
509 break;
510 case SME_AC_VI:
511 ac = SME_AC_BE;
512 up = SME_QOS_WMM_UP_BE;
513 break;
514 case SME_AC_BE:
515 ac = SME_AC_BK;
516 up = SME_QOS_WMM_UP_BK;
517 break;
518 default:
519 ac = SME_AC_BK;
520 up = SME_QOS_WMM_UP_BK;
521 isDefaultAc = true;
522 break;
523 }
524 if (isDefaultAc)
525 break;
526 }
527 skb->priority = up;
528 skb->queue_mapping = hdd_linux_up_to_ac_map[up];
529 }
530
Kabilan Kannan36090ce2016-05-03 19:28:44 -0700531#ifdef QCA_PKT_PROTO_TRACE
532 if ((hdd_ctx->config->gEnableDebugLog & CDS_PKT_TRAC_TYPE_EAPOL) ||
533 (hdd_ctx->config->gEnableDebugLog & CDS_PKT_TRAC_TYPE_DHCP)) {
534 proto_type = cds_pkt_get_proto_type(skb,
535 hdd_ctx->config->gEnableDebugLog,
536 0);
537 if (CDS_PKT_TRAC_TYPE_EAPOL & proto_type) {
538 cds_pkt_trace_buf_update("ST:T:EPL");
539 } else if (CDS_PKT_TRAC_TYPE_DHCP & proto_type) {
540 cds_pkt_trace_buf_update("ST:T:DHC");
541 }
542 }
543#endif /* QCA_PKT_PROTO_TRACE */
544
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800545 pAdapter->stats.tx_bytes += skb->len;
Kabilan Kannan36090ce2016-05-03 19:28:44 -0700546
547 if (hdd_ctx->enable_tdls_connection_tracker)
548 wlan_hdd_tdls_update_tx_pkt_cnt(pAdapter, skb);
549
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800550 ++pAdapter->stats.tx_packets;
551
Nirav Shah5e74bb82016-07-20 16:01:27 +0530552 hdd_event_eapol_log(skb, QDF_TX);
Nirav Shah0d58a7e2016-04-26 22:54:12 +0530553 qdf_dp_trace_log_pkt(pAdapter->sessionId, skb, QDF_TX);
Nirav Shahcbc6d722016-03-01 16:24:53 +0530554 QDF_NBUF_CB_TX_PACKET_TRACK(skb) = QDF_NBUF_TX_PKT_DATA_TRACK;
555 QDF_NBUF_UPDATE_TX_PKT_COUNT(skb, QDF_NBUF_TX_PKT_HDD);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800556
Nirav Shah0d58a7e2016-04-26 22:54:12 +0530557 qdf_dp_trace_set_track(skb, QDF_TX);
558 DPTRACE(qdf_dp_trace(skb, QDF_DP_TRACE_HDD_TX_PACKET_PTR_RECORD,
559 (uint8_t *)&skb->data, sizeof(skb->data), QDF_TX));
560 DPTRACE(qdf_dp_trace(skb, QDF_DP_TRACE_HDD_TX_PACKET_RECORD,
561 (uint8_t *)skb->data, qdf_nbuf_len(skb), QDF_TX));
Nirav Shah07e39a62016-04-25 17:46:40 +0530562 if (qdf_nbuf_len(skb) > QDF_DP_TRACE_RECORD_SIZE) {
Nirav Shah0d58a7e2016-04-26 22:54:12 +0530563 DPTRACE(qdf_dp_trace(skb, QDF_DP_TRACE_HDD_TX_PACKET_RECORD,
564 (uint8_t *)&skb->data[QDF_DP_TRACE_RECORD_SIZE],
565 (qdf_nbuf_len(skb)-QDF_DP_TRACE_RECORD_SIZE), QDF_TX));
Nirav Shah07e39a62016-04-25 17:46:40 +0530566 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800567
Dhanashri Atre168d2b42016-02-22 14:43:06 -0800568 /* Check if station is connected */
Dhanashri Atreb08959a2016-03-01 17:28:03 -0800569 if (OL_TXRX_PEER_STATE_CONN ==
Dhanashri Atre168d2b42016-02-22 14:43:06 -0800570 pAdapter->aStaInfo[STAId].tlSTAState) {
571 QDF_TRACE(QDF_MODULE_ID_HDD_DATA,
572 QDF_TRACE_LEVEL_WARN,
573 "%s: station is not connected..dropping pkt",
574 __func__);
Nirav Shahdf3659e2016-06-27 12:26:28 +0530575 ++pAdapter->hdd_stats.hddTxRxStats.txXmitDroppedAC[ac];
576 goto drop_pkt;
Dhanashri Atre168d2b42016-02-22 14:43:06 -0800577 }
578
Dhanashri Atre168d2b42016-02-22 14:43:06 -0800579 /*
Ravi Joshi24477b72016-07-19 15:45:09 -0700580 * If a transmit function is not registered, drop packet
581 */
Dhanashri Atre168d2b42016-02-22 14:43:06 -0800582 if (!pAdapter->tx_fn) {
583 QDF_TRACE(QDF_MODULE_ID_HDD_SAP_DATA, QDF_TRACE_LEVEL_INFO_HIGH,
584 "%s: TX function not registered by the data path",
585 __func__);
Nirav Shahdf3659e2016-06-27 12:26:28 +0530586 ++pAdapter->hdd_stats.hddTxRxStats.txXmitDroppedAC[ac];
Dhanashri Atre168d2b42016-02-22 14:43:06 -0800587 goto drop_pkt;
588 }
589
590 if (pAdapter->tx_fn(ol_txrx_get_vdev_by_sta_id(STAId),
591 (qdf_nbuf_t) skb) != NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530592 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_WARN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800593 "%s: Failed to send packet to txrx for staid:%d",
594 __func__, STAId);
Nirav Shahdf3659e2016-06-27 12:26:28 +0530595 ++pAdapter->hdd_stats.hddTxRxStats.txXmitDroppedAC[ac];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800596 goto drop_pkt;
597 }
598 dev->trans_start = jiffies;
599
600 return NETDEV_TX_OK;
601
602drop_pkt:
603
Nirav Shahdf3659e2016-06-27 12:26:28 +0530604 if (skb) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530605 DPTRACE(qdf_dp_trace(skb, QDF_DP_TRACE_DROP_PACKET_RECORD,
Nirav Shahdf3659e2016-06-27 12:26:28 +0530606 (uint8_t *)skb->data, qdf_nbuf_len(skb), QDF_TX));
607 if (qdf_nbuf_len(skb) > QDF_DP_TRACE_RECORD_SIZE)
608 DPTRACE(qdf_dp_trace(skb,
609 QDF_DP_TRACE_DROP_PACKET_RECORD,
610 (uint8_t *)&skb->data[QDF_DP_TRACE_RECORD_SIZE],
611 (qdf_nbuf_len(skb)-QDF_DP_TRACE_RECORD_SIZE),
612 QDF_TX));
613
614 kfree_skb(skb);
615 }
616
617drop_pkt_accounting:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800618
619 ++pAdapter->stats.tx_dropped;
620 ++pAdapter->hdd_stats.hddTxRxStats.txXmitDropped;
Nirav Shahdf3659e2016-06-27 12:26:28 +0530621
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800622 return NETDEV_TX_OK;
623}
624
625/**
Deepak Dhamdhere5872c8c2016-06-02 15:51:47 -0700626 * hdd_get_peer_sta_id() - Get the StationID using the Peer Mac address
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800627 * @pHddStaCtx: pointer to HDD Station Context
628 * @pMacAddress: pointer to Peer Mac address
629 * @staID: pointer to returned Station Index
630 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530631 * Return: QDF_STATUS_SUCCESS/QDF_STATUS_E_FAILURE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800632 */
633
Deepak Dhamdhere5872c8c2016-06-02 15:51:47 -0700634QDF_STATUS hdd_get_peer_sta_id(hdd_station_ctx_t *pHddStaCtx,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530635 struct qdf_mac_addr *pMacAddress, uint8_t *staId)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800636{
637 uint8_t idx;
638
Naveen Rawatc45d1622016-07-05 12:20:09 -0700639 for (idx = 0; idx < MAX_PEERS; idx++) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530640 if (!qdf_mem_cmp(&pHddStaCtx->conn_info.peerMacAddress[idx],
Anurag Chouhan6d760662016-02-20 16:05:43 +0530641 pMacAddress, QDF_MAC_ADDR_SIZE)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800642 *staId = pHddStaCtx->conn_info.staId[idx];
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530643 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800644 }
645 }
646
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530647 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800648}
649
650/**
651 * __hdd_tx_timeout() - TX timeout handler
652 * @dev: pointer to network device
653 *
654 * This function is registered as a netdev ndo_tx_timeout method, and
655 * is invoked by the kernel if the driver takes too long to transmit a
656 * frame.
657 *
658 * Return: None
659 */
660static void __hdd_tx_timeout(struct net_device *dev)
661{
Nirav Shah89223f72016-03-01 18:10:38 +0530662 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
663 hdd_context_t *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800664 struct netdev_queue *txq;
665 int i = 0;
666
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530667 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800668 "%s: Transmission timeout occurred jiffies %lu trans_start %lu",
669 __func__, jiffies, dev->trans_start);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530670 DPTRACE(qdf_dp_trace(NULL, QDF_DP_TRACE_HDD_TX_TIMEOUT,
Nirav Shah0d58a7e2016-04-26 22:54:12 +0530671 NULL, 0, QDF_TX));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800672
673 /* Getting here implies we disabled the TX queues for too
674 * long. Queues are disabled either because of disassociation
675 * or low resource scenarios. In case of disassociation it is
676 * ok to ignore this. But if associated, we have do possible
677 * recovery here
678 */
679
680 for (i = 0; i < NUM_TX_QUEUES; i++) {
681 txq = netdev_get_tx_queue(dev, i);
Nirav Shah89223f72016-03-01 18:10:38 +0530682 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800683 "Queue%d status: %d txq->trans_start %lu",
684 i, netif_tx_queue_stopped(txq), txq->trans_start);
685 }
686
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530687 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800688 "carrier state: %d", netif_carrier_ok(dev));
Nirav Shah89223f72016-03-01 18:10:38 +0530689 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
690 wlan_hdd_display_netif_queue_history(hdd_ctx);
691 ol_tx_dump_flow_pool_info();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800692}
693
694/**
695 * hdd_tx_timeout() - Wrapper function to protect __hdd_tx_timeout from SSR
696 * @dev: pointer to net_device structure
697 *
698 * Function called by OS if there is any timeout during transmission.
699 * Since HDD simply enqueues packet and returns control to OS right away,
700 * this would never be invoked
701 *
702 * Return: none
703 */
704void hdd_tx_timeout(struct net_device *dev)
705{
706 cds_ssr_protect(__func__);
707 __hdd_tx_timeout(dev);
708 cds_ssr_unprotect(__func__);
709}
710
711/**
712 * @hdd_init_tx_rx() - Initialize Tx/RX module
713 * @pAdapter: pointer to adapter context
714 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530715 * Return: QDF_STATUS_E_FAILURE if any errors encountered,
716 * QDF_STATUS_SUCCESS otherwise
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800717 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530718QDF_STATUS hdd_init_tx_rx(hdd_adapter_t *pAdapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800719{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530720 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800721
722 if (NULL == pAdapter) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530723 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800724 FL("pAdapter is NULL"));
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530725 QDF_ASSERT(0);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530726 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800727 }
728
729 return status;
730}
731
732/**
733 * @hdd_deinit_tx_rx() - Deinitialize Tx/RX module
734 * @pAdapter: pointer to adapter context
735 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530736 * Return: QDF_STATUS_E_FAILURE if any errors encountered,
737 * QDF_STATUS_SUCCESS otherwise
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800738 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530739QDF_STATUS hdd_deinit_tx_rx(hdd_adapter_t *pAdapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800740{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530741 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800742
743 if (NULL == pAdapter) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530744 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800745 FL("pAdapter is NULL"));
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530746 QDF_ASSERT(0);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530747 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800748 }
749
750 return status;
751}
752
753/**
Manjunathappa Prakash59f861d2016-04-21 10:33:31 -0700754 * hdd_mon_rx_packet_cbk() - Receive callback registered with OL layer.
755 * @context: [in] pointer to qdf context
756 * @rxBuf: [in] pointer to rx qdf_nbuf
757 *
758 * TL will call this to notify the HDD when one or more packets were
759 * received for a registered STA.
760 *
761 * Return: QDF_STATUS_E_FAILURE if any errors encountered, QDF_STATUS_SUCCESS
762 * otherwise
763 */
764static QDF_STATUS hdd_mon_rx_packet_cbk(void *context, qdf_nbuf_t rxbuf)
765{
766 hdd_adapter_t *adapter;
767 int rxstat;
768 struct sk_buff *skb;
769 struct sk_buff *skb_next;
770 unsigned int cpu_index;
771
772 /* Sanity check on inputs */
773 if ((NULL == context) || (NULL == rxbuf)) {
774 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_ERROR,
775 "%s: Null params being passed", __func__);
776 return QDF_STATUS_E_FAILURE;
777 }
778
779 adapter = (hdd_adapter_t *)context;
780 if ((NULL == adapter) || (WLAN_HDD_ADAPTER_MAGIC != adapter->magic)) {
781 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_ERROR,
782 "invalid adapter %p", adapter);
783 return QDF_STATUS_E_FAILURE;
784 }
785
786 cpu_index = wlan_hdd_get_cpu();
787
788 /* walk the chain until all are processed */
789 skb = (struct sk_buff *) rxbuf;
790 while (NULL != skb) {
791 skb_next = skb->next;
792 skb->dev = adapter->dev;
793
794 ++adapter->hdd_stats.hddTxRxStats.rxPackets[cpu_index];
795 ++adapter->stats.rx_packets;
796 adapter->stats.rx_bytes += skb->len;
797
798 /* Remove SKB from internal tracking table before submitting
799 * it to stack
800 */
801 qdf_net_buf_debug_release_skb(skb);
802
803 /*
804 * If this is not a last packet on the chain
805 * Just put packet into backlog queue, not scheduling RX sirq
806 */
807 if (skb->next) {
808 rxstat = netif_rx(skb);
809 } else {
810 /*
811 * This is the last packet on the chain
812 * Scheduling rx sirq
813 */
814 rxstat = netif_rx_ni(skb);
815 }
816
817 if (NET_RX_SUCCESS == rxstat)
818 ++adapter->
819 hdd_stats.hddTxRxStats.rxDelivered[cpu_index];
820 else
821 ++adapter->hdd_stats.hddTxRxStats.rxRefused[cpu_index];
822
823 skb = skb_next;
824 }
825
826 adapter->dev->last_rx = jiffies;
827
828 return QDF_STATUS_SUCCESS;
829}
830
831/**
Naveen Rawatf28315c2016-06-29 18:06:02 -0700832 * hdd_get_peer_idx() - Get the idx for given address in peer table
833 * @sta_ctx: pointer to HDD Station Context
834 * @addr: pointer to Peer Mac address
835 *
836 * Return: index when success else INVALID_PEER_IDX
837 */
838int hdd_get_peer_idx(hdd_station_ctx_t *sta_ctx, struct qdf_mac_addr *addr)
839{
840 uint8_t idx;
841
Naveen Rawatc45d1622016-07-05 12:20:09 -0700842 for (idx = 0; idx < MAX_PEERS; idx++) {
Naveen Rawatf28315c2016-06-29 18:06:02 -0700843 if (sta_ctx->conn_info.staId[idx] == 0)
844 continue;
845 if (qdf_mem_cmp(&sta_ctx->conn_info.peerMacAddress[idx],
846 addr, sizeof(struct qdf_mac_addr)))
847 continue;
848 return idx;
849 }
850
851 return INVALID_PEER_IDX;
852}
853
854/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800855 * hdd_rx_packet_cbk() - Receive packet handler
Dhanashri Atre182b0272016-02-17 15:35:07 -0800856 * @context: pointer to HDD context
Nirav Shahcbc6d722016-03-01 16:24:53 +0530857 * @rxBuf: pointer to rx qdf_nbuf
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800858 *
859 * Receive callback registered with TL. TL will call this to notify
860 * the HDD when one or more packets were received for a registered
861 * STA.
862 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530863 * Return: QDF_STATUS_E_FAILURE if any errors encountered,
864 * QDF_STATUS_SUCCESS otherwise
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800865 */
Dhanashri Atre182b0272016-02-17 15:35:07 -0800866QDF_STATUS hdd_rx_packet_cbk(void *context, qdf_nbuf_t rxBuf)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800867{
868 hdd_adapter_t *pAdapter = NULL;
869 hdd_context_t *pHddCtx = NULL;
870 int rxstat;
871 struct sk_buff *skb = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800872 hdd_station_ctx_t *pHddStaCtx = NULL;
873 unsigned int cpu_index;
874
875 /* Sanity check on inputs */
Dhanashri Atre182b0272016-02-17 15:35:07 -0800876 if (unlikely((NULL == context) || (NULL == rxBuf))) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530877 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800878 "%s: Null params being passed", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530879 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800880 }
881
Dhanashri Atre182b0272016-02-17 15:35:07 -0800882 pAdapter = (hdd_adapter_t *)context;
883 if (unlikely(WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530884 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_FATAL,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800885 "Magic cookie(%x) for adapter sanity verification is invalid",
886 pAdapter->magic);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530887 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800888 }
889
Dhanashri Atre182b0272016-02-17 15:35:07 -0800890 pHddCtx = pAdapter->pHddCtx;
891 if (unlikely(NULL == pHddCtx)) {
892 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_ERROR,
893 "%s: HDD context is Null", __func__);
894 return QDF_STATUS_E_FAILURE;
895 }
896
897 cpu_index = wlan_hdd_get_cpu();
898
899 skb = (struct sk_buff *)rxBuf;
900
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800901 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
902 if ((pHddStaCtx->conn_info.proxyARPService) &&
903 cfg80211_is_gratuitous_arp_unsolicited_na(skb)) {
904 ++pAdapter->hdd_stats.hddTxRxStats.rxDropped[cpu_index];
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530905 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800906 "%s: Dropping HS 2.0 Gratuitous ARP or Unsolicited NA",
907 __func__);
908 /* Remove SKB from internal tracking table before submitting
909 * it to stack
910 */
Nirav Shahcbc6d722016-03-01 16:24:53 +0530911 qdf_nbuf_free(skb);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530912 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800913 }
914
Nirav Shah5e74bb82016-07-20 16:01:27 +0530915 hdd_event_eapol_log(skb, QDF_RX);
Nirav Shah0d58a7e2016-04-26 22:54:12 +0530916 DPTRACE(qdf_dp_trace(rxBuf,
917 QDF_DP_TRACE_RX_HDD_PACKET_PTR_RECORD,
918 qdf_nbuf_data_addr(rxBuf),
919 sizeof(qdf_nbuf_data(rxBuf)), QDF_RX));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800920
Kabilan Kannan36090ce2016-05-03 19:28:44 -0700921 if (pHddCtx->enable_tdls_connection_tracker)
922 wlan_hdd_tdls_update_rx_pkt_cnt(pAdapter, skb);
923
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800924 skb->dev = pAdapter->dev;
925 skb->protocol = eth_type_trans(skb, skb->dev);
926 ++pAdapter->hdd_stats.hddTxRxStats.rxPackets[cpu_index];
927 ++pAdapter->stats.rx_packets;
928 pAdapter->stats.rx_bytes += skb->len;
929#ifdef WLAN_FEATURE_HOLD_RX_WAKELOCK
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530930 qdf_wake_lock_timeout_acquire(&pHddCtx->rx_wake_lock,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800931 HDD_WAKE_LOCK_DURATION,
932 WIFI_POWER_EVENT_WAKELOCK_HOLD_RX);
933#endif
934
935 /* Remove SKB from internal tracking table before submitting
936 * it to stack
937 */
Nirav Shahcbc6d722016-03-01 16:24:53 +0530938 qdf_net_buf_debug_release_skb(rxBuf);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800939
940 if (HDD_LRO_NO_RX ==
941 hdd_lro_rx(pHddCtx, pAdapter, skb)) {
Orhan K AKYILDIZ4f20db52015-12-30 12:35:44 -0800942 if (hdd_napi_enabled(HDD_NAPI_ANY) &&
Nirav Shahbd36b062016-07-18 11:12:59 +0530943 !pHddCtx->enableRxThread)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800944 rxstat = netif_receive_skb(skb);
945 else
946 rxstat = netif_rx_ni(skb);
947
948 if (NET_RX_SUCCESS == rxstat)
949 ++pAdapter->hdd_stats.hddTxRxStats.
950 rxDelivered[cpu_index];
951 else
952 ++pAdapter->hdd_stats.hddTxRxStats.
953 rxRefused[cpu_index];
954
955 } else {
956 ++pAdapter->hdd_stats.hddTxRxStats.
957 rxDelivered[cpu_index];
958 }
959
960 pAdapter->dev->last_rx = jiffies;
961
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530962 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800963}
964
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800965/**
966 * hdd_reason_type_to_string() - return string conversion of reason type
967 * @reason: reason type
968 *
969 * This utility function helps log string conversion of reason type.
970 *
971 * Return: string conversion of device mode, if match found;
972 * "Unknown" otherwise.
973 */
974const char *hdd_reason_type_to_string(enum netif_reason_type reason)
975{
976 switch (reason) {
977 CASE_RETURN_STRING(WLAN_CONTROL_PATH);
978 CASE_RETURN_STRING(WLAN_DATA_FLOW_CONTROL);
979 CASE_RETURN_STRING(WLAN_FW_PAUSE);
980 CASE_RETURN_STRING(WLAN_TX_ABORT);
981 CASE_RETURN_STRING(WLAN_VDEV_STOP);
982 CASE_RETURN_STRING(WLAN_PEER_UNAUTHORISED);
983 CASE_RETURN_STRING(WLAN_THERMAL_MITIGATION);
984 default:
Nirav Shah617cff92016-04-25 10:24:24 +0530985 return "Invalid";
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800986 }
987}
988
989/**
990 * hdd_action_type_to_string() - return string conversion of action type
991 * @action: action type
992 *
993 * This utility function helps log string conversion of action_type.
994 *
995 * Return: string conversion of device mode, if match found;
996 * "Unknown" otherwise.
997 */
998const char *hdd_action_type_to_string(enum netif_action_type action)
999{
1000
1001 switch (action) {
1002 CASE_RETURN_STRING(WLAN_STOP_ALL_NETIF_QUEUE);
1003 CASE_RETURN_STRING(WLAN_START_ALL_NETIF_QUEUE);
1004 CASE_RETURN_STRING(WLAN_WAKE_ALL_NETIF_QUEUE);
1005 CASE_RETURN_STRING(WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER);
1006 CASE_RETURN_STRING(WLAN_START_ALL_NETIF_QUEUE_N_CARRIER);
1007 CASE_RETURN_STRING(WLAN_NETIF_TX_DISABLE);
1008 CASE_RETURN_STRING(WLAN_NETIF_TX_DISABLE_N_CARRIER);
1009 CASE_RETURN_STRING(WLAN_NETIF_CARRIER_ON);
1010 CASE_RETURN_STRING(WLAN_NETIF_CARRIER_OFF);
1011 default:
Nirav Shah617cff92016-04-25 10:24:24 +05301012 return "Invalid";
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001013 }
1014}
1015
1016/**
1017 * wlan_hdd_update_queue_oper_stats - update queue operation statistics
1018 * @adapter: adapter handle
1019 * @action: action type
1020 * @reason: reason type
1021 */
1022static void wlan_hdd_update_queue_oper_stats(hdd_adapter_t *adapter,
1023 enum netif_action_type action, enum netif_reason_type reason)
1024{
1025 switch (action) {
1026 case WLAN_STOP_ALL_NETIF_QUEUE:
1027 case WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER:
1028 case WLAN_NETIF_TX_DISABLE:
1029 case WLAN_NETIF_TX_DISABLE_N_CARRIER:
1030 adapter->queue_oper_stats[reason].pause_count++;
1031 break;
1032 case WLAN_START_ALL_NETIF_QUEUE:
1033 case WLAN_WAKE_ALL_NETIF_QUEUE:
1034 case WLAN_START_ALL_NETIF_QUEUE_N_CARRIER:
1035 adapter->queue_oper_stats[reason].unpause_count++;
1036 break;
1037 default:
1038 break;
1039 }
1040
1041 return;
1042}
1043
1044/**
Nirav Shah89223f72016-03-01 18:10:38 +05301045 * wlan_hdd_update_txq_timestamp() - update txq timestamp
1046 * @dev: net device
1047 *
1048 * Return: none
1049 */
1050void wlan_hdd_update_txq_timestamp(struct net_device *dev)
1051{
1052 struct netdev_queue *txq;
1053 int i;
1054 bool unlock;
1055
1056 for (i = 0; i < NUM_TX_QUEUES; i++) {
1057 txq = netdev_get_tx_queue(dev, i);
1058 unlock = __netif_tx_trylock(txq);
1059 txq_trans_update(txq);
1060 if (unlock == true)
1061 __netif_tx_unlock(txq);
1062 }
1063}
1064
1065/**
Nirav Shah617cff92016-04-25 10:24:24 +05301066 * wlan_hdd_update_unpause_time() - update unpause time
1067 * @adapter: adapter handle
1068 *
1069 * Return: none
1070 */
1071static void wlan_hdd_update_unpause_time(hdd_adapter_t *adapter)
1072{
1073 qdf_time_t curr_time = qdf_system_ticks();
1074
1075 adapter->total_unpause_time += curr_time - adapter->last_time;
1076 adapter->last_time = curr_time;
1077}
1078
1079/**
1080 * wlan_hdd_update_pause_time() - update pause time
1081 * @adapter: adapter handle
1082 *
1083 * Return: none
1084 */
Nirav Shahda008342016-05-17 18:50:40 +05301085static void wlan_hdd_update_pause_time(hdd_adapter_t *adapter,
1086 uint32_t temp_map)
Nirav Shah617cff92016-04-25 10:24:24 +05301087{
1088 qdf_time_t curr_time = qdf_system_ticks();
Nirav Shahda008342016-05-17 18:50:40 +05301089 uint8_t i;
1090 qdf_time_t pause_time;
Nirav Shah617cff92016-04-25 10:24:24 +05301091
Nirav Shahda008342016-05-17 18:50:40 +05301092 pause_time = curr_time - adapter->last_time;
1093 adapter->total_pause_time += pause_time;
Nirav Shah617cff92016-04-25 10:24:24 +05301094 adapter->last_time = curr_time;
Nirav Shahda008342016-05-17 18:50:40 +05301095
1096 for (i = 0; i < WLAN_REASON_TYPE_MAX; i++) {
1097 if (temp_map & (1 << i)) {
1098 adapter->queue_oper_stats[i].total_pause_time +=
1099 pause_time;
1100 break;
1101 }
1102 }
1103
Nirav Shah617cff92016-04-25 10:24:24 +05301104}
1105
1106/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001107 * wlan_hdd_netif_queue_control() - Use for netif_queue related actions
1108 * @adapter: adapter handle
1109 * @action: action type
1110 * @reason: reason type
1111 *
1112 * This is single function which is used for netif_queue related
1113 * actions like start/stop of network queues and on/off carrier
1114 * option.
1115 *
1116 * Return: None
1117 */
1118void wlan_hdd_netif_queue_control(hdd_adapter_t *adapter,
1119 enum netif_action_type action, enum netif_reason_type reason)
1120{
Nirav Shahda008342016-05-17 18:50:40 +05301121 uint32_t temp_map;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001122
1123 if ((!adapter) || (WLAN_HDD_ADAPTER_MAGIC != adapter->magic) ||
1124 (!adapter->dev)) {
1125 hdd_err("adapter is invalid");
1126 return;
1127 }
1128
1129 switch (action) {
1130
1131 case WLAN_NETIF_CARRIER_ON:
1132 netif_carrier_on(adapter->dev);
1133 break;
1134
1135 case WLAN_NETIF_CARRIER_OFF:
1136 netif_carrier_off(adapter->dev);
1137 break;
1138
1139 case WLAN_STOP_ALL_NETIF_QUEUE:
1140 spin_lock_bh(&adapter->pause_map_lock);
Nirav Shah89223f72016-03-01 18:10:38 +05301141 if (!adapter->pause_map) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001142 netif_tx_stop_all_queues(adapter->dev);
Nirav Shah89223f72016-03-01 18:10:38 +05301143 wlan_hdd_update_txq_timestamp(adapter->dev);
Nirav Shah617cff92016-04-25 10:24:24 +05301144 wlan_hdd_update_unpause_time(adapter);
Nirav Shah89223f72016-03-01 18:10:38 +05301145 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001146 adapter->pause_map |= (1 << reason);
1147 spin_unlock_bh(&adapter->pause_map_lock);
1148 break;
1149
1150 case WLAN_START_ALL_NETIF_QUEUE:
1151 spin_lock_bh(&adapter->pause_map_lock);
Nirav Shahda008342016-05-17 18:50:40 +05301152 temp_map = adapter->pause_map;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001153 adapter->pause_map &= ~(1 << reason);
Nirav Shah617cff92016-04-25 10:24:24 +05301154 if (!adapter->pause_map) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001155 netif_tx_start_all_queues(adapter->dev);
Nirav Shahda008342016-05-17 18:50:40 +05301156 wlan_hdd_update_pause_time(adapter, temp_map);
Nirav Shah617cff92016-04-25 10:24:24 +05301157 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001158 spin_unlock_bh(&adapter->pause_map_lock);
1159 break;
1160
1161 case WLAN_WAKE_ALL_NETIF_QUEUE:
1162 spin_lock_bh(&adapter->pause_map_lock);
Nirav Shahda008342016-05-17 18:50:40 +05301163 temp_map = adapter->pause_map;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001164 adapter->pause_map &= ~(1 << reason);
Nirav Shah617cff92016-04-25 10:24:24 +05301165 if (!adapter->pause_map) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001166 netif_tx_wake_all_queues(adapter->dev);
Nirav Shahda008342016-05-17 18:50:40 +05301167 wlan_hdd_update_pause_time(adapter, temp_map);
Nirav Shah617cff92016-04-25 10:24:24 +05301168 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001169 spin_unlock_bh(&adapter->pause_map_lock);
1170 break;
1171
1172 case WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER:
1173 spin_lock_bh(&adapter->pause_map_lock);
Nirav Shah89223f72016-03-01 18:10:38 +05301174 if (!adapter->pause_map) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001175 netif_tx_stop_all_queues(adapter->dev);
Nirav Shah89223f72016-03-01 18:10:38 +05301176 wlan_hdd_update_txq_timestamp(adapter->dev);
Nirav Shah617cff92016-04-25 10:24:24 +05301177 wlan_hdd_update_unpause_time(adapter);
Nirav Shah89223f72016-03-01 18:10:38 +05301178 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001179 adapter->pause_map |= (1 << reason);
1180 netif_carrier_off(adapter->dev);
1181 spin_unlock_bh(&adapter->pause_map_lock);
1182 break;
1183
1184 case WLAN_START_ALL_NETIF_QUEUE_N_CARRIER:
1185 spin_lock_bh(&adapter->pause_map_lock);
1186 netif_carrier_on(adapter->dev);
Nirav Shahda008342016-05-17 18:50:40 +05301187 temp_map = adapter->pause_map;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001188 adapter->pause_map &= ~(1 << reason);
Nirav Shah617cff92016-04-25 10:24:24 +05301189 if (!adapter->pause_map) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001190 netif_tx_start_all_queues(adapter->dev);
Nirav Shahda008342016-05-17 18:50:40 +05301191 wlan_hdd_update_pause_time(adapter, temp_map);
Nirav Shah617cff92016-04-25 10:24:24 +05301192 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001193 spin_unlock_bh(&adapter->pause_map_lock);
1194 break;
1195
1196 case WLAN_NETIF_TX_DISABLE:
1197 spin_lock_bh(&adapter->pause_map_lock);
Nirav Shah89223f72016-03-01 18:10:38 +05301198 if (!adapter->pause_map) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001199 netif_tx_disable(adapter->dev);
Nirav Shah89223f72016-03-01 18:10:38 +05301200 wlan_hdd_update_txq_timestamp(adapter->dev);
Nirav Shah617cff92016-04-25 10:24:24 +05301201 wlan_hdd_update_unpause_time(adapter);
Nirav Shah89223f72016-03-01 18:10:38 +05301202 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001203 adapter->pause_map |= (1 << reason);
1204 spin_unlock_bh(&adapter->pause_map_lock);
1205 break;
1206
1207 case WLAN_NETIF_TX_DISABLE_N_CARRIER:
1208 spin_lock_bh(&adapter->pause_map_lock);
Nirav Shah89223f72016-03-01 18:10:38 +05301209 if (!adapter->pause_map) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001210 netif_tx_disable(adapter->dev);
Nirav Shah89223f72016-03-01 18:10:38 +05301211 wlan_hdd_update_txq_timestamp(adapter->dev);
Nirav Shah617cff92016-04-25 10:24:24 +05301212 wlan_hdd_update_unpause_time(adapter);
Nirav Shah89223f72016-03-01 18:10:38 +05301213 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001214 adapter->pause_map |= (1 << reason);
1215 netif_carrier_off(adapter->dev);
1216 spin_unlock_bh(&adapter->pause_map_lock);
1217 break;
1218
1219 default:
1220 hdd_err("unsupported action %d", action);
1221 }
1222
1223 spin_lock_bh(&adapter->pause_map_lock);
1224 if (adapter->pause_map & (1 << WLAN_PEER_UNAUTHORISED))
1225 wlan_hdd_process_peer_unauthorised_pause(adapter);
1226 spin_unlock_bh(&adapter->pause_map_lock);
1227
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001228 wlan_hdd_update_queue_oper_stats(adapter, action, reason);
1229
1230 adapter->queue_oper_history[adapter->history_index].time =
Anurag Chouhan50220ce2016-02-18 20:11:33 +05301231 qdf_system_ticks();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001232 adapter->queue_oper_history[adapter->history_index].netif_action =
1233 action;
1234 adapter->queue_oper_history[adapter->history_index].netif_reason =
1235 reason;
1236 adapter->queue_oper_history[adapter->history_index].pause_map =
1237 adapter->pause_map;
1238 if (++adapter->history_index == WLAN_HDD_MAX_HISTORY_ENTRY)
1239 adapter->history_index = 0;
1240
1241 return;
1242}
1243
Manjunathappa Prakash59f861d2016-04-21 10:33:31 -07001244/**
1245 * hdd_set_mon_rx_cb() - Set Monitor mode Rx callback
1246 * @dev: Pointer to net_device structure
1247 *
1248 * Return: 0 for success; non-zero for failure
1249 */
1250int hdd_set_mon_rx_cb(struct net_device *dev)
1251{
1252 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
1253 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1254 int ret;
1255 QDF_STATUS qdf_status;
1256 struct ol_txrx_desc_type sta_desc = {0};
1257 struct ol_txrx_ops txrx_ops;
1258
1259 ret = wlan_hdd_validate_context(hdd_ctx);
1260 if (0 != ret)
1261 return ret;
1262
1263 qdf_mem_zero(&txrx_ops, sizeof(txrx_ops));
1264 txrx_ops.rx.rx = hdd_mon_rx_packet_cbk;
1265 ol_txrx_vdev_register(
1266 ol_txrx_get_vdev_from_vdev_id(adapter->sessionId),
1267 adapter, &txrx_ops);
1268 /* peer is created wma_vdev_attach->wma_create_peer */
1269 qdf_status = ol_txrx_register_peer(&sta_desc);
1270 if (QDF_STATUS_SUCCESS != qdf_status) {
1271 hdd_err("WLANTL_RegisterSTAClient() failed to register. Status= %d [0x%08X]",
1272 qdf_status, qdf_status);
1273 goto exit;
1274 }
1275
1276 qdf_status = sme_create_mon_session(hdd_ctx->hHal,
1277 adapter->macAddressCurrent.bytes);
1278 if (QDF_STATUS_SUCCESS != qdf_status) {
1279 hdd_err("sme_create_mon_session() failed to register. Status= %d [0x%08X]",
1280 qdf_status, qdf_status);
1281 }
1282exit:
1283 ret = qdf_status_to_os_return(qdf_status);
1284 return ret;
1285}
Nirav Shahbd36b062016-07-18 11:12:59 +05301286
1287/**
1288 * hdd_send_rps_ind() - send rps indication to daemon
1289 * @adapter: adapter context
1290 *
1291 * If RPS feature enabled by INI, send RPS enable indication to daemon
1292 * Indication contents is the name of interface to find correct sysfs node
1293 * Should send all available interfaces
1294 *
1295 * Return: none
1296 */
1297void hdd_send_rps_ind(hdd_adapter_t *adapter)
1298{
1299 int i;
1300 uint8_t cpu_map_list_len = 0;
1301 hdd_context_t *hdd_ctxt = NULL;
1302 struct wlan_rps_data rps_data;
1303
1304 if (!adapter) {
1305 hdd_err("adapter is NULL");
1306 return;
1307 }
1308
1309 hdd_ctxt = WLAN_HDD_GET_CTX(adapter);
1310 rps_data.num_queues = NUM_TX_QUEUES;
1311
1312 hdd_info("cpu_map_list '%s'", hdd_ctxt->config->cpu_map_list);
1313
1314 /* in case no cpu map list is provided, simply return */
1315 if (!strlen(hdd_ctxt->config->cpu_map_list)) {
1316 hdd_err("no cpu map list found");
1317 goto err;
1318 }
1319
1320 if (QDF_STATUS_SUCCESS !=
1321 hdd_hex_string_to_u16_array(hdd_ctxt->config->cpu_map_list,
1322 rps_data.cpu_map_list,
1323 &cpu_map_list_len,
1324 WLAN_SVC_IFACE_NUM_QUEUES)) {
1325 hdd_err("invalid cpu map list");
1326 goto err;
1327 }
1328
1329 rps_data.num_queues =
1330 (cpu_map_list_len < rps_data.num_queues) ?
1331 cpu_map_list_len : rps_data.num_queues;
1332
1333 for (i = 0; i < rps_data.num_queues; i++) {
1334 hdd_info("cpu_map_list[%d] = 0x%x",
1335 i, rps_data.cpu_map_list[i]);
1336 }
1337
1338 strlcpy(rps_data.ifname, adapter->dev->name,
1339 sizeof(rps_data.ifname));
1340 wlan_hdd_send_svc_nlink_msg(WLAN_SVC_RPS_ENABLE_IND,
1341 &rps_data, sizeof(rps_data));
1342
1343err:
1344 hdd_err("Wrong RPS configuration. enabling rx_thread");
1345 hdd_ctxt->rps = false;
1346 hdd_ctxt->enableRxThread = true;
1347}
1348
1349