aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/base/core.c130
-rw-r--r--drivers/platform/msm/mhi/mhi_sys.c28
-rw-r--r--drivers/soc/qcom/Kconfig16
-rw-r--r--drivers/soc/qcom/Makefile2
-rw-r--r--drivers/soc/qcom/core_ctl.c1086
-rw-r--r--drivers/soc/qcom/core_ctl_helper.c62
-rw-r--r--drivers/soc/qcom/peripheral-loader.c2
-rw-r--r--drivers/soc/qcom/socinfo.c40
-rw-r--r--drivers/staging/prima/CORE/DXE/src/wlan_qct_dxe.c16
-rw-r--r--drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg80211.h62
-rw-r--r--drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h63
-rw-r--r--drivers/staging/prima/CORE/HDD/inc/wlan_hdd_wmm.h10
-rw-r--r--drivers/staging/prima/CORE/HDD/src/wlan_hdd_assoc.c1
-rw-r--r--drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c491
-rw-r--r--drivers/staging/prima/CORE/HDD/src/wlan_hdd_early_suspend.c7
-rw-r--r--drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c1
-rw-r--r--drivers/staging/prima/CORE/HDD/src/wlan_hdd_p2p.c32
-rw-r--r--drivers/staging/prima/CORE/HDD/src/wlan_hdd_tx_rx.c166
-rw-r--r--drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c17
-rw-r--r--drivers/staging/prima/CORE/HDD/src/wlan_hdd_wmm.c33
-rw-r--r--drivers/staging/prima/CORE/MAC/inc/aniGlobal.h7
-rw-r--r--drivers/staging/prima/CORE/MAC/inc/sirApi.h55
-rw-r--r--drivers/staging/prima/CORE/MAC/inc/wniApi.h1
-rw-r--r--drivers/staging/prima/CORE/MAC/src/include/sirParams.h7
-rw-r--r--drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessMessageQueue.c1
-rw-r--r--drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessSmeReqMessages.c54
-rw-r--r--drivers/staging/prima/CORE/SME/inc/sme_Api.h13
-rw-r--r--drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c12
-rw-r--r--drivers/staging/prima/CORE/SME/src/sme_common/sme_Api.c164
-rw-r--r--drivers/staging/prima/CORE/SYS/legacy/src/utils/src/macTrace.c4
-rw-r--r--drivers/staging/prima/CORE/TL/inc/wlan_qct_tl.h9
-rw-r--r--drivers/staging/prima/CORE/TL/src/wlan_qct_tl.c47
-rw-r--r--drivers/staging/prima/CORE/TL/src/wlan_qct_tl_ba.c8
-rw-r--r--drivers/staging/prima/CORE/TL/src/wlan_qct_tli.h2
-rw-r--r--drivers/staging/prima/CORE/VOSS/inc/vos_api.h7
-rw-r--r--drivers/staging/prima/CORE/VOSS/inc/vos_packet.h24
-rw-r--r--drivers/staging/prima/CORE/VOSS/src/vos_api.c265
-rw-r--r--drivers/staging/prima/CORE/VOSS/src/vos_packet.c31
-rw-r--r--drivers/staging/prima/CORE/WDA/inc/wlan_qct_wda.h14
-rw-r--r--drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c403
-rw-r--r--drivers/staging/prima/CORE/WDA/src/wlan_qct_wda_ds.c4
-rw-r--r--drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi.h53
-rw-r--r--drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi_bd.h11
-rw-r--r--drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi_dp.h3
-rw-r--r--drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi_i.h35
-rw-r--r--drivers/staging/prima/CORE/WDI/CP/src/wlan_qct_wdi.c316
-rw-r--r--drivers/staging/prima/CORE/WDI/CP/src/wlan_qct_wdi_dp.c6
-rw-r--r--drivers/staging/prima/CORE/WDI/DP/inc/wlan_qct_wdi_ds.h7
-rw-r--r--drivers/staging/prima/CORE/WDI/DP/src/wlan_qct_wdi_ds.c15
-rw-r--r--drivers/staging/prima/CORE/WDI/TRP/DTS/src/wlan_qct_wdi_dts.c9
-rw-r--r--drivers/staging/prima/CORE/WDI/WPAL/inc/wlan_qct_pal_api.h4
-rw-r--r--drivers/staging/prima/CORE/WDI/WPAL/src/wlan_qct_pal_api.c19
-rw-r--r--drivers/staging/prima/riva/inc/wlan_hal_msg.h69
-rw-r--r--drivers/usb/phy/phy-ab8500-usb.c2
-rw-r--r--drivers/usb/phy/phy-gpio-vbus-usb.c2
-rw-r--r--drivers/usb/phy/phy-mxs-usb.c2
-rw-r--r--drivers/usb/phy/phy.c4
57 files changed, 2667 insertions, 1287 deletions
diff --git a/drivers/base/core.c b/drivers/base/core.c
index a1b4e620f96..60d4786c4cc 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -403,6 +403,36 @@ static ssize_t store_uevent(struct device *dev, struct device_attribute *attr,
static struct device_attribute uevent_attr =
__ATTR(uevent, S_IRUGO | S_IWUSR, show_uevent, store_uevent);
+static ssize_t show_online(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ bool val;
+
+ lock_device_hotplug();
+ val = !dev->offline;
+ unlock_device_hotplug();
+ return sprintf(buf, "%u\n", val);
+}
+
+static ssize_t store_online(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ bool val;
+ int ret;
+
+ ret = strtobool(buf, &val);
+ if (ret < 0)
+ return ret;
+
+ lock_device_hotplug();
+ ret = val ? device_online(dev) : device_offline(dev);
+ unlock_device_hotplug();
+ return ret < 0 ? ret : count;
+}
+
+static struct device_attribute online_attr =
+ __ATTR(online, S_IRUGO | S_IWUSR, show_online, store_online);
+
static int device_add_attributes(struct device *dev,
struct device_attribute *attrs)
{
@@ -516,6 +546,12 @@ static int device_add_attrs(struct device *dev)
if (error)
goto err_remove_type_groups;
+ if (device_supports_offline(dev) && !dev->offline_disabled) {
+ error = device_create_file(dev, &online_attr);
+ if (error)
+ goto err_remove_type_groups;
+ }
+
return 0;
err_remove_type_groups:
@@ -536,6 +572,7 @@ static void device_remove_attrs(struct device *dev)
struct class *class = dev->class;
const struct device_type *type = dev->type;
+ device_remove_file(dev, &online_attr);
device_remove_groups(dev, dev->groups);
if (type)
@@ -1460,6 +1497,99 @@ EXPORT_SYMBOL_GPL(put_device);
EXPORT_SYMBOL_GPL(device_create_file);
EXPORT_SYMBOL_GPL(device_remove_file);
+static DEFINE_MUTEX(device_hotplug_lock);
+
+void lock_device_hotplug(void)
+{
+ mutex_lock(&device_hotplug_lock);
+}
+
+void unlock_device_hotplug(void)
+{
+ mutex_unlock(&device_hotplug_lock);
+}
+
+static int device_check_offline(struct device *dev, void *not_used)
+{
+ int ret;
+
+ ret = device_for_each_child(dev, NULL, device_check_offline);
+ if (ret)
+ return ret;
+
+ return device_supports_offline(dev) && !dev->offline ? -EBUSY : 0;
+}
+
+/**
+ * device_offline - Prepare the device for hot-removal.
+ * @dev: Device to be put offline.
+ *
+ * Execute the device bus type's .offline() callback, if present, to prepare
+ * the device for a subsequent hot-removal. If that succeeds, the device must
+ * not be used until either it is removed or its bus type's .online() callback
+ * is executed.
+ *
+ * Call under device_hotplug_lock.
+ */
+int device_offline(struct device *dev)
+{
+ int ret;
+
+ if (dev->offline_disabled)
+ return -EPERM;
+
+ ret = device_for_each_child(dev, NULL, device_check_offline);
+ if (ret)
+ return ret;
+
+ device_lock(dev);
+ if (device_supports_offline(dev)) {
+ if (dev->offline) {
+ ret = 1;
+ } else {
+ ret = dev->bus->offline(dev);
+ if (!ret) {
+ kobject_uevent(&dev->kobj, KOBJ_OFFLINE);
+ dev->offline = true;
+ }
+ }
+ }
+ device_unlock(dev);
+
+ return ret;
+}
+
+/**
+ * device_online - Put the device back online after successful device_offline().
+ * @dev: Device to be put back online.
+ *
+ * If device_offline() has been successfully executed for @dev, but the device
+ * has not been removed subsequently, execute its bus type's .online() callback
+ * to indicate that the device can be used again.
+ *
+ * Call under device_hotplug_lock.
+ */
+int device_online(struct device *dev)
+{
+ int ret = 0;
+
+ device_lock(dev);
+ if (device_supports_offline(dev)) {
+ if (dev->offline) {
+ ret = dev->bus->online(dev);
+ if (!ret) {
+ kobject_uevent(&dev->kobj, KOBJ_ONLINE);
+ dev->offline = false;
+ }
+ } else {
+ ret = 1;
+ }
+ }
+ device_unlock(dev);
+
+ return ret;
+}
+
struct root_device {
struct device dev;
struct module *owner;
diff --git a/drivers/platform/msm/mhi/mhi_sys.c b/drivers/platform/msm/mhi/mhi_sys.c
index 07cd5f8b03c..231c70b7905 100644
--- a/drivers/platform/msm/mhi/mhi_sys.c
+++ b/drivers/platform/msm/mhi/mhi_sys.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -187,22 +187,6 @@ static const struct file_operations mhi_dbgfs_ev_fops = {
.write = NULL,
};
-static ssize_t mhi_dbgfs_trigger_msi(struct file *fp, const char __user *buf,
- size_t count, loff_t *offp)
-{
- u32 msi_nr = 0;
- void *irq_ctxt = &((mhi_devices.device_list[0]).pcie_device->dev);
- if (copy_from_user(&msi_nr, buf, sizeof(msi_nr)))
- return -ENOMEM;
- mhi_msi_handlr(msi_nr, irq_ctxt);
- return 0;
-}
-
-static const struct file_operations mhi_dbgfs_trigger_msi_fops = {
- .read = NULL,
- .write = mhi_dbgfs_trigger_msi,
-};
-
static ssize_t mhi_dbgfs_state_read(struct file *fp, char __user *buf,
size_t count, loff_t *offp)
{
@@ -311,7 +295,6 @@ int mhi_init_debugfs(struct mhi_device_ctxt *mhi_dev_ctxt)
{
struct dentry *mhi_chan_stats;
struct dentry *mhi_state_stats;
- struct dentry *mhi_msi_trigger;
struct dentry *mhi_ev_stats;
mhi_dev_ctxt->mhi_parent_folder =
debugfs_create_dir("mhi", NULL);
@@ -340,21 +323,12 @@ int mhi_init_debugfs(struct mhi_device_ctxt *mhi_dev_ctxt)
&mhi_dbgfs_state_fops);
if (mhi_state_stats == NULL)
goto clean_ev_stats;
- mhi_msi_trigger = debugfs_create_file("mhi_msi_trigger",
- 0444,
- mhi_dev_ctxt->mhi_parent_folder,
- mhi_dev_ctxt,
- &mhi_dbgfs_trigger_msi_fops);
- if (mhi_msi_trigger == NULL)
- goto clean_state;
mhi_dev_ctxt->chan_info = kmalloc(MHI_LOG_SIZE, GFP_KERNEL);
if (mhi_dev_ctxt->chan_info == NULL)
goto clean_all;
return 0;
clean_all:
- debugfs_remove(mhi_msi_trigger);
-clean_state:
debugfs_remove(mhi_state_stats);
clean_ev_stats:
debugfs_remove(mhi_ev_stats);
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index 2f524d78545..05b3e9c3c09 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -546,22 +546,6 @@ config MSM_PACMAN
This driver allows reconfiguration of the Bus Access Manager
Low Speed Peripheral (BLSP) ownership.
-config MSM_CORE_CTL_HELPER
- tristate "Core control helper functions for dynamically hotplug CPUs"
- help
- Provide helper functions for core control driver. Core control
- driver dynamicatlly hotplugs CPUs from kernel based on current
- system load and state. It also supports limiting min and
- max online CPUs from userspace.
-
-config MSM_CORE_CTL
- select MSM_CORE_CTL_HELPER
- tristate "Core control driver to dynamically hotplug CPUs"
- help
- Support for dynamicatlly hotplugging CPUs from kernel based on
- current system load and state. It also supports limiting min and
- max online CPUs from userspace.
-
config MSM_PERFORMANCE
tristate "Core control driver to support userspace hotplug requests"
help
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index 2eb79f0b841..2621f65fc7e 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -56,8 +56,6 @@ obj-$(CONFIG_MSM_OCMEM) += ocmem.o ocmem_allocator.o ocmem_notifier.o
obj-$(CONFIG_MSM_OCMEM) += ocmem_sched.o ocmem_api.o ocmem_rdm.o ocmem_core.o
obj-$(CONFIG_MSM_PERFORMANCE) += msm_performance.o
-obj-$(CONFIG_MSM_CORE_CTL_HELPER) += core_ctl_helper.o
-obj-$(CONFIG_MSM_CORE_CTL) += core_ctl.o
ifdef CONFIG_MSM_SUBSYSTEM_RESTART
obj-y += subsystem_notif.o
diff --git a/drivers/soc/qcom/core_ctl.c b/drivers/soc/qcom/core_ctl.c
deleted file mode 100644
index 0148630a7e0..00000000000
--- a/drivers/soc/qcom/core_ctl.c
+++ /dev/null
@@ -1,1086 +0,0 @@
-/*
- * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials provided
- * with the distribution.
- * * Neither the name of The Linux Foundation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
- * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
- * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/init.h>
-#include <linux/notifier.h>
-#include <linux/cpu.h>
-#include <linux/moduleparam.h>
-#include <linux/cpumask.h>
-#include <linux/cpufreq.h>
-#include <linux/timer.h>
-#include <linux/kthread.h>
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <soc/qcom/core_ctl.h>
-#include <linux/mutex.h>
-
-#include <trace/events/power.h>
-
-#define MAX_CPUS_PER_GROUP 4
-
-struct cpu_data {
- /* Per CPU data. */
- bool inited;
- bool online;
- bool rejected;
- bool is_busy;
- bool not_preferred;
- unsigned int busy;
- unsigned int cpu;
- struct list_head sib;
- unsigned int first_cpu;
- struct list_head pending_sib;
-
- /* Per cluster data set only on first CPU */
- unsigned int min_cpus;
- unsigned int max_cpus;
- unsigned int offline_delay_ms;
- unsigned int busy_up_thres[MAX_CPUS_PER_GROUP];
- unsigned int busy_down_thres[MAX_CPUS_PER_GROUP];
- unsigned int online_cpus;
- unsigned int avail_cpus;
- unsigned int num_cpus;
- unsigned int need_cpus;
- unsigned int task_thres;
- s64 need_ts;
- struct list_head lru;
- bool pending;
- spinlock_t pending_lock;
- bool is_big_cluster;
- int nrrun;
- bool nrrun_changed;
- struct timer_list timer;
- struct task_struct *hotplug_thread;
- struct kobject kobj;
- struct list_head pending_lru;
-};
-
-static DEFINE_PER_CPU(struct cpu_data, cpu_state);
-static DEFINE_SPINLOCK(state_lock);
-static DEFINE_SPINLOCK(pending_lru_lock);
-static DEFINE_MUTEX(lru_lock);
-
-static void apply_need(struct cpu_data *f);
-static void wake_up_hotplug_thread(struct cpu_data *state);
-static void add_to_pending_lru(struct cpu_data *state);
-static void update_lru(struct cpu_data *state);
-
-/* ========================= sysfs interface =========================== */
-
-static ssize_t store_min_cpus(struct cpu_data *state,
- const char *buf, size_t count)
-{
- unsigned int val;
-
- if (sscanf(buf, "%u\n", &val) != 1)
- return -EINVAL;
-
- state->min_cpus = min(val, state->max_cpus);
- wake_up_hotplug_thread(state);
-
- return count;
-}
-
-static ssize_t show_min_cpus(struct cpu_data *state, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "%u\n", state->min_cpus);
-}
-
-static ssize_t store_max_cpus(struct cpu_data *state,
- const char *buf, size_t count)
-{
- unsigned int val;
-
- if (sscanf(buf, "%u\n", &val) != 1)
- return -EINVAL;
-
- val = min(val, state->num_cpus);
- state->max_cpus = val;
- state->min_cpus = min(state->min_cpus, state->max_cpus);
- wake_up_hotplug_thread(state);
-
- return count;
-}
-
-static ssize_t show_max_cpus(struct cpu_data *state, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "%u\n", state->max_cpus);
-}
-
-static ssize_t store_offline_delay_ms(struct cpu_data *state,
- const char *buf, size_t count)
-{
- unsigned int val;
-
- if (sscanf(buf, "%u\n", &val) != 1)
- return -EINVAL;
-
- state->offline_delay_ms = val;
- apply_need(state);
-
- return count;
-}
-
-static ssize_t show_task_thres(struct cpu_data *state, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "%u\n", state->task_thres);
-}
-
-static ssize_t store_task_thres(struct cpu_data *state,
- const char *buf, size_t count)
-{
- unsigned int val;
-
- if (sscanf(buf, "%u\n", &val) != 1)
- return -EINVAL;
-
- if (val < state->num_cpus)
- return -EINVAL;
-
- state->task_thres = val;
- apply_need(state);
-
- return count;
-}
-
-static ssize_t show_offline_delay_ms(struct cpu_data *state, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "%u\n", state->offline_delay_ms);
-}
-
-static ssize_t store_busy_up_thres(struct cpu_data *state,
- const char *buf, size_t count)
-{
- unsigned int val[MAX_CPUS_PER_GROUP];
- int ret, i;
-
- ret = sscanf(buf, "%u %u %u %u\n", &val[0], &val[1], &val[2], &val[3]);
- if (ret != 1 && ret != state->num_cpus)
- return -EINVAL;
-
- if (ret == 1) {
- for (i = 0; i < state->num_cpus; i++)
- state->busy_up_thres[i] = val[0];
- } else {
- for (i = 0; i < state->num_cpus; i++)
- state->busy_up_thres[i] = val[i];
- }
- apply_need(state);
- return count;
-}
-
-static ssize_t show_busy_up_thres(struct cpu_data *state, char *buf)
-{
- int i, count = 0;
- for (i = 0; i < state->num_cpus; i++)
- count += snprintf(buf + count, PAGE_SIZE - count, "%u ",
- state->busy_up_thres[i]);
- count += snprintf(buf + count, PAGE_SIZE - count, "\n");
- return count;
-}
-
-static ssize_t store_busy_down_thres(struct cpu_data *state,
- const char *buf, size_t count)
-{
- unsigned int val[MAX_CPUS_PER_GROUP];
- int ret, i;
-
- ret = sscanf(buf, "%u %u %u %u\n", &val[0], &val[1], &val[2], &val[3]);
- if (ret != 1 && ret != state->num_cpus)
- return -EINVAL;
-
- if (ret == 1) {
- for (i = 0; i < state->num_cpus; i++)
- state->busy_down_thres[i] = val[0];
- } else {
- for (i = 0; i < state->num_cpus; i++)
- state->busy_down_thres[i] = val[i];
- }
- apply_need(state);
- return count;
-}
-
-static ssize_t show_busy_down_thres(struct cpu_data *state, char *buf)
-{
- int i, count = 0;
- for (i = 0; i < state->num_cpus; i++)
- count += snprintf(buf + count, PAGE_SIZE - count, "%u ",
- state->busy_down_thres[i]);
- count += snprintf(buf + count, PAGE_SIZE - count, "\n");
- return count;
-}
-
-static ssize_t store_is_big_cluster(struct cpu_data *state,
- const char *buf, size_t count)
-{
- unsigned int val;
-
- if (sscanf(buf, "%u\n", &val) != 1)
- return -EINVAL;
-
- state->is_big_cluster = val ? 1 : 0;
- return count;
-}
-
-static ssize_t show_is_big_cluster(struct cpu_data *state, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "%u\n", state->is_big_cluster);
-}
-
-static ssize_t show_cpus(struct cpu_data *state, char *buf)
-{
- struct cpu_data *c;
- ssize_t count = 0;
- unsigned long flags;
-
- spin_lock_irqsave(&state_lock, flags);
- list_for_each_entry(c, &state->lru, sib) {
- count += snprintf(buf + count, PAGE_SIZE - count,
- "CPU%u (%s)\n", c->cpu,
- c->online ? "Online" : "Offline");
- }
- spin_unlock_irqrestore(&state_lock, flags);
- return count;
-}
-
-static ssize_t show_need_cpus(struct cpu_data *state, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "%u\n", state->need_cpus);
-}
-
-static ssize_t show_online_cpus(struct cpu_data *state, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "%u\n", state->online_cpus);
-}
-
-static ssize_t show_global_state(struct cpu_data *state, char *buf)
-{
- struct cpu_data *c;
- ssize_t count = 0;
- unsigned int cpu;
-
- for_each_possible_cpu(cpu) {
- count += snprintf(buf + count, PAGE_SIZE - count,
- "CPU%u\n", cpu);
- c = &per_cpu(cpu_state, cpu);
- if (!c->inited)
- continue;
- count += snprintf(buf + count, PAGE_SIZE - count,
- "\tCPU: %u\n", c->cpu);
- count += snprintf(buf + count, PAGE_SIZE - count,
- "\tOnline: %u\n", c->online);
- count += snprintf(buf + count, PAGE_SIZE - count,
- "\tRejected: %u\n", c->rejected);
- count += snprintf(buf + count, PAGE_SIZE - count,
- "\tFirst CPU: %u\n", c->first_cpu);
- count += snprintf(buf + count, PAGE_SIZE - count,
- "\tBusy%%: %u\n", c->busy);
- count += snprintf(buf + count, PAGE_SIZE - count,
- "\tIs busy: %u\n", c->is_busy);
- if (c->cpu != c->first_cpu)
- continue;
- count += snprintf(buf + count, PAGE_SIZE- count,
- "\tNr running: %u\n", c->nrrun);
- count += snprintf(buf + count, PAGE_SIZE - count,
- "\tAvail CPUs: %u\n", c->avail_cpus);
- count += snprintf(buf + count, PAGE_SIZE - count,
- "\tNeed CPUs: %u\n", c->need_cpus);
- }
-
- return count;
-}
-
-static ssize_t store_not_preferred(struct cpu_data *state,
- const char *buf, size_t count)
-{
- struct cpu_data *c;
- unsigned int i, first_cpu;
- unsigned int val[MAX_CPUS_PER_GROUP];
- int ret;
-
- ret = sscanf(buf, "%u %u %u %u\n", &val[0], &val[1], &val[2], &val[3]);
- if (ret != 1 && ret != state->num_cpus)
- return -EINVAL;
-
- first_cpu = state->first_cpu;
-
- for (i = 0; i < state->num_cpus; i++) {
- c = &per_cpu(cpu_state, first_cpu);
- c->not_preferred = val[i];
- first_cpu++;
- }
-
- return count;
-}
-
-static ssize_t show_not_preferred(struct cpu_data *state, char *buf)
-{
- struct cpu_data *c;
- ssize_t count = 0;
- unsigned int i, first_cpu;
-
- first_cpu = state->first_cpu;
-
- for (i = 0; i < state->num_cpus; i++) {
- c = &per_cpu(cpu_state, first_cpu);
- count += snprintf(buf + count, PAGE_SIZE - count,
- "\tCPU:%d %u\n", first_cpu, c->not_preferred);
- first_cpu++;
- }
-
- return count;
-}
-
-struct core_ctl_attr {
- struct attribute attr;
- ssize_t (*show)(struct cpu_data *, char *);
- ssize_t (*store)(struct cpu_data *, const char *, size_t count);
-};
-
-#define core_ctl_attr_ro(_name) \
-static struct core_ctl_attr _name = \
-__ATTR(_name, 0444, show_##_name, NULL)
-
-#define core_ctl_attr_rw(_name) \
-static struct core_ctl_attr _name = \
-__ATTR(_name, 0644, show_##_name, store_##_name)
-
-core_ctl_attr_rw(min_cpus);
-core_ctl_attr_rw(max_cpus);
-core_ctl_attr_rw(offline_delay_ms);
-core_ctl_attr_rw(busy_up_thres);
-core_ctl_attr_rw(busy_down_thres);
-core_ctl_attr_rw(task_thres);
-core_ctl_attr_rw(is_big_cluster);
-core_ctl_attr_ro(cpus);
-core_ctl_attr_ro(need_cpus);
-core_ctl_attr_ro(online_cpus);
-core_ctl_attr_ro(global_state);
-core_ctl_attr_rw(not_preferred);
-
-static struct attribute *default_attrs[] = {
- &min_cpus.attr,
- &max_cpus.attr,
- &offline_delay_ms.attr,
- &busy_up_thres.attr,
- &busy_down_thres.attr,
- &task_thres.attr,
- &is_big_cluster.attr,
- &cpus.attr,
- &need_cpus.attr,
- &online_cpus.attr,
- &global_state.attr,
- &not_preferred.attr,
- NULL
-};
-
-#define to_cpu_data(k) container_of(k, struct cpu_data, kobj)
-#define to_attr(a) container_of(a, struct core_ctl_attr, attr)
-static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf)
-{
- struct cpu_data *data = to_cpu_data(kobj);
- struct core_ctl_attr *cattr = to_attr(attr);
- ssize_t ret = -EIO;
-
- if (cattr->show)
- ret = cattr->show(data, buf);
-
- return ret;
-}
-
-static ssize_t store(struct kobject *kobj, struct attribute *attr,
- const char *buf, size_t count)
-{
- struct cpu_data *data = to_cpu_data(kobj);
- struct core_ctl_attr *cattr = to_attr(attr);
- ssize_t ret = -EIO;
-
- if (cattr->store)
- ret = cattr->store(data, buf, count);
-
- return ret;
-}
-
-static const struct sysfs_ops sysfs_ops = {
- .show = show,
- .store = store,
-};
-
-static struct kobj_type ktype_core_ctl = {
- .sysfs_ops = &sysfs_ops,
- .default_attrs = default_attrs,
-};
-
-/* ==================== runqueue based core count =================== */
-
-#define RQ_AVG_TOLERANCE 2
-#define RQ_AVG_DEFAULT_MS 20
-#define NR_RUNNING_TOLERANCE 5
-static unsigned int rq_avg_period_ms = RQ_AVG_DEFAULT_MS;
-module_param(rq_avg_period_ms, uint, 0644);
-
-static s64 rq_avg_timestamp_ms;
-static struct timer_list rq_avg_timer;
-
-static void update_running_avg(bool trigger_update)
-{
- int cpu;
- struct cpu_data *pcpu;
- int avg, iowait_avg, big_avg, old_nrrun;
- s64 now;
- unsigned long flags;
-
- spin_lock_irqsave(&state_lock, flags);
-
- now = core_ctl_get_time();
- if (now - rq_avg_timestamp_ms < rq_avg_period_ms - RQ_AVG_TOLERANCE) {
- spin_unlock_irqrestore(&state_lock, flags);
- return;
- }
- rq_avg_timestamp_ms = now;
- sched_get_nr_running_avg(&avg, &iowait_avg, &big_avg);
-
- spin_unlock_irqrestore(&state_lock, flags);
-
- /*
- * Round up to the next integer if the average nr running tasks
- * is within NR_RUNNING_TOLERANCE/100 of the next integer.
- * If normal rounding up is used, it will allow a transient task
- * to trigger online event. By the time core is onlined, the task
- * has finished.
- * Rounding to closest suffers same problem because scheduler
- * might only provide running stats per jiffy, and a transient
- * task could skew the number for one jiffy. If core control
- * samples every 2 jiffies, it will observe 0.5 additional running
- * average which rounds up to 1 task.
- */
- avg = (avg + NR_RUNNING_TOLERANCE) / 100;
- big_avg = (big_avg + NR_RUNNING_TOLERANCE) / 100;
-
- for_each_possible_cpu(cpu) {
- pcpu = &per_cpu(cpu_state, cpu);
- if (!pcpu->inited || pcpu->first_cpu != cpu)
- continue;
- old_nrrun = pcpu->nrrun;
- /*
- * Big cluster only need to take care of big tasks, but if
- * there are not enough big cores, big tasks need to be run
- * on little as well. Thus for little's runqueue stat, it
- * has to use overall runqueue average, or derive what big
- * tasks would have to be run on little. The latter approach
- * is not easy to get given core control reacts much slower
- * than scheduler, and can't predict scheduler's behavior.
- */
- pcpu->nrrun = pcpu->is_big_cluster ? big_avg : avg;
- if (pcpu->nrrun != old_nrrun) {
- if (trigger_update)
- apply_need(pcpu);
- else
- pcpu->nrrun_changed = true;
- }
- }
-}
-
-/* adjust needed CPUs based on current runqueue information */
-static unsigned int apply_task_need(struct cpu_data *f, unsigned int new_need)
-{
- /* Online all cores if there are enough tasks */
- if (f->nrrun >= f->task_thres)
- return f->num_cpus;
-
- /* only online more cores if there are tasks to run */
- if (f->nrrun > new_need)
- return new_need + 1;
-
- return new_need;
-}
-
-static u64 round_to_nw_start(void)
-{
- unsigned long step = msecs_to_jiffies(rq_avg_period_ms);
- u64 jif = get_jiffies_64();
-
- do_div(jif, step);
- return (jif + 1) * step;
-}
-
-static void rq_avg_timer_func(unsigned long not_used)
-{
- update_running_avg(true);
- mod_timer(&rq_avg_timer, round_to_nw_start());
-}
-
-/* ======================= load based core count ====================== */
-
-static unsigned int apply_limits(struct cpu_data *f, unsigned int need_cpus)
-{
- return min(max(f->min_cpus, need_cpus), f->max_cpus);
-}
-
-static bool eval_need(struct cpu_data *f)
-{
- unsigned long flags;
- struct cpu_data *c;
- unsigned int need_cpus = 0, last_need, thres_idx;
- int ret = 0;
- bool need_flag = false;
- s64 now;
-
- if (unlikely(!f->inited))
- return 0;
-
- spin_lock_irqsave(&state_lock, flags);
- thres_idx = f->online_cpus ? f->online_cpus - 1 : 0;
- list_for_each_entry(c, &f->lru, sib) {
- if (c->busy >= f->busy_up_thres[thres_idx])
- c->is_busy = true;
- else if (c->busy < f->busy_down_thres[thres_idx])
- c->is_busy = false;
- need_cpus += c->is_busy;
- }
- need_cpus = apply_task_need(f, need_cpus);
- need_flag = apply_limits(f, need_cpus) != apply_limits(f, f->need_cpus);
- last_need = f->need_cpus;
-
- now = core_ctl_get_time();
-
- if (need_cpus == last_need) {
- f->need_ts = now;
- spin_unlock_irqrestore(&state_lock, flags);
- return 0;
- }
-
- if (need_cpus > last_need) {
- ret = 1;
- } else if (need_cpus < last_need) {
- s64 elapsed = now - f->need_ts;
- if (elapsed >= f->offline_delay_ms) {
- ret = 1;
- } else {
- mod_timer(&f->timer, jiffies +
- msecs_to_jiffies(f->offline_delay_ms));
- }
- }
-
- if (ret) {
- f->need_ts = now;
- f->need_cpus = need_cpus;
- }
-
- trace_core_ctl_eval_need(f->cpu, last_need, need_cpus, ret && need_flag);
- spin_unlock_irqrestore(&state_lock, flags);
-
- return ret && need_flag;
-}
-
-static void apply_need(struct cpu_data *f)
-{
- if (eval_need(f))
- wake_up_hotplug_thread(f);
-}
-
-static int core_ctl_set_busy(unsigned int cpu, unsigned int busy)
-{
- struct cpu_data *c = &per_cpu(cpu_state, cpu);
- struct cpu_data *f;
- unsigned int old_is_busy = c->is_busy;
-
- if (!c->inited)
- return 0;
- f = &per_cpu(cpu_state, c->first_cpu);
-
- update_running_avg(false);
- if (c->busy == busy && !f->nrrun_changed)
- return 0;
- c->busy = busy;
- f->nrrun_changed = false;
-
- apply_need(f);
- trace_core_ctl_set_busy(cpu, busy, old_is_busy, c->is_busy);
- return 0;
-}
-
-/* ========================= core count enforcement ==================== */
-
-/*
- * If current thread is hotplug thread, don't attempt to wake up
- * itself or other hotplug threads because it will deadlock. Instead,
- * schedule a timer to fire in next timer tick and wake up the thread.
- */
-static void wake_up_hotplug_thread(struct cpu_data *state)
-{
- unsigned long flags;
- int cpu;
- struct cpu_data *pcpu;
- bool no_wakeup = false;
-
- for_each_possible_cpu(cpu) {
- pcpu = &per_cpu(cpu_state, cpu);
- if (cpu != pcpu->first_cpu)
- continue;
- if (pcpu->hotplug_thread == current) {
- no_wakeup = true;
- break;
- }
- }
-
- spin_lock_irqsave(&state->pending_lock, flags);
- state->pending = true;
- spin_unlock_irqrestore(&state->pending_lock, flags);
-
- if (no_wakeup) {
- spin_lock_irqsave(&state_lock, flags);
- mod_timer(&state->timer, jiffies);
- spin_unlock_irqrestore(&state_lock, flags);
- } else {
- wake_up_process(state->hotplug_thread);
- }
-}
-
-static void core_ctl_timer_func(unsigned long cpu)
-{
- struct cpu_data *state = &per_cpu(cpu_state, cpu);
- unsigned long flags;
-
- if (eval_need(state)) {
- spin_lock_irqsave(&state->pending_lock, flags);
- state->pending = true;
- spin_unlock_irqrestore(&state->pending_lock, flags);
- wake_up_process(state->hotplug_thread);
- }
-
-}
-
-static void update_lru(struct cpu_data *f)
-{
- struct cpu_data *c, *tmp;
- unsigned long flags;
-
- spin_lock_irqsave(&pending_lru_lock, flags);
- spin_lock(&state_lock);
-
- list_for_each_entry_safe(c, tmp, &f->pending_lru, pending_sib) {
- list_del_init(&c->pending_sib);
- list_del(&c->sib);
- list_add_tail(&c->sib, &f->lru);
- }
-
- spin_unlock(&state_lock);
- spin_unlock_irqrestore(&pending_lru_lock, flags);
-}
-
-static void __ref do_hotplug(struct cpu_data *f)
-{
- unsigned int need;
- struct cpu_data *c, *tmp;
-
- need = apply_limits(f, f->need_cpus);
- pr_debug("Trying to adjust group %u to %u\n", f->first_cpu, need);
-
- mutex_lock(&lru_lock);
- if (f->online_cpus > need) {
- list_for_each_entry_safe(c, tmp, &f->lru, sib) {
- if (!c->online)
- continue;
-
- if (f->online_cpus == need)
- break;
-
- /* Don't offline busy CPUs. */
- if (c->is_busy)
- continue;
-
- pr_debug("Trying to Offline CPU%u\n", c->cpu);
- if (cpu_down(c->cpu))
- pr_debug("Unable to Offline CPU%u\n", c->cpu);
- }
-
- /*
- * If the number of online CPUs is within the limits, then
- * don't force any busy CPUs offline.
- */
- if (f->online_cpus <= f->max_cpus)
- goto done;
-
- list_for_each_entry_safe(c, tmp, &f->lru, sib) {
- if (!c->online)
- continue;
-
- if (f->online_cpus <= f->max_cpus)
- break;
-
- pr_debug("Trying to Offline CPU%u\n", c->cpu);
- if (cpu_down(c->cpu))
- pr_debug("Unable to Offline CPU%u\n", c->cpu);
- }
- } else if (f->online_cpus < need) {
- list_for_each_entry_safe(c, tmp, &f->lru, sib) {
- if (c->online || c->rejected || c->not_preferred)
- continue;
- if (f->online_cpus == need)
- break;
-
- pr_debug("Trying to Online CPU%u\n", c->cpu);
- if (core_ctl_online_core(c->cpu))
- pr_debug("Unable to Online CPU%u\n", c->cpu);
- }
-
- if (f->online_cpus == need)
- goto done;
-
-
- list_for_each_entry_safe(c, tmp, &f->lru, sib) {
- if (c->online || c->rejected || !c->not_preferred)
- continue;
- if (f->online_cpus == need)
- break;
-
- pr_debug("Trying to Online CPU%u\n", c->cpu);
- if (core_ctl_online_core(c->cpu))
- pr_debug("Unable to Online CPU%u\n", c->cpu);
- }
- }
-done:
- mutex_unlock(&lru_lock);
- update_lru(f);
-}
-
-static int __ref try_hotplug(void *data)
-{
- struct cpu_data *f = data;
- unsigned long flags;
-
- while (1) {
- set_current_state(TASK_INTERRUPTIBLE);
- spin_lock_irqsave(&f->pending_lock, flags);
- if (!f->pending) {
- spin_unlock_irqrestore(&f->pending_lock, flags);
- schedule();
- if (kthread_should_stop())
- break;
- spin_lock_irqsave(&f->pending_lock, flags);
- }
- set_current_state(TASK_RUNNING);
- f->pending = false;
- spin_unlock_irqrestore(&f->pending_lock, flags);
-
- do_hotplug(f);
- }
-
- return 0;
-}
-
-static void add_to_pending_lru(struct cpu_data *state)
-{
- unsigned long flags;
- struct cpu_data *f = &per_cpu(cpu_state, state->first_cpu);
-
- spin_lock_irqsave(&pending_lru_lock, flags);
-
- if (!list_empty(&state->pending_sib))
- list_del(&state->pending_sib);
- list_add_tail(&state->pending_sib, &f->pending_lru);
-
- spin_unlock_irqrestore(&pending_lru_lock, flags);
-}
-
-static int __ref cpu_callback(struct notifier_block *nfb,
- unsigned long action, void *hcpu)
-{
- uint32_t cpu = (uintptr_t)hcpu;
- struct cpu_data *state = &per_cpu(cpu_state, cpu);
- struct cpu_data *f;
- int ret = NOTIFY_OK;
- unsigned long flags;
-
- /* Don't affect suspend resume */
- if (action & CPU_TASKS_FROZEN)
- return NOTIFY_OK;
-
- if (unlikely(!state->inited))
- return NOTIFY_OK;
-
- f = &per_cpu(cpu_state, state->first_cpu);
-
- switch (action) {
- case CPU_UP_PREPARE:
-
- /* If online state of CPU somehow got out of sync, fix it. */
- if (state->online) {
- f->online_cpus--;
- state->online = false;
- pr_warn("CPU%d offline when state is online\n", cpu);
- }
-
- if (state->rejected) {
- state->rejected = false;
- f->avail_cpus++;
- }
-
- /*
- * If a CPU is in the process of coming up, mark it as online
- * so that there's no race with hotplug thread bringing up more
- * CPUs than necessary.
- */
- if (apply_limits(f, f->need_cpus) <= f->online_cpus) {
- pr_debug("Prevent CPU%d onlining\n", cpu);
- ret = NOTIFY_BAD;
- } else {
- state->online = true;
- f->online_cpus++;
- }
- break;
-
- case CPU_ONLINE:
- /*
- * Moving to the end of the list should only happen in
- * CPU_ONLINE and not on CPU_UP_PREPARE to prevent an
- * infinite list traversal when thermal (or other entities)
- * reject trying to online CPUs.
- */
- ret = mutex_trylock(&lru_lock);
- if (ret) {
- spin_lock_irqsave(&state_lock, flags);
- list_del(&state->sib);
- list_add_tail(&state->sib, &f->lru);
- spin_unlock_irqrestore(&state_lock, flags);
- mutex_unlock(&lru_lock);
- } else {
- /*
- * lru_lock is held by our hotplug thread to
- * prevent concurrent access of lru list. The updates
- * are maintained in pending_lru list and lru is
- * updated at the end of do_hotplug().
- */
- add_to_pending_lru(state);
- }
- break;
-
- case CPU_DEAD:
- /* Move a CPU to the end of the LRU when it goes offline. */
- ret = mutex_trylock(&lru_lock);
- if (ret) {
- spin_lock_irqsave(&state_lock, flags);
- list_del(&state->sib);
- list_add_tail(&state->sib, &f->lru);
- spin_unlock_irqrestore(&state_lock, flags);
- mutex_unlock(&lru_lock);
- } else {
- add_to_pending_lru(state);
- }
- /* Fall through */
-
- case CPU_UP_CANCELED:
-
- /* If online state of CPU somehow got out of sync, fix it. */
- if (!state->online) {
- f->online_cpus++;
- pr_warn("CPU%d online when state is offline\n", cpu);
- }
-
- if (!state->rejected && action == CPU_UP_CANCELED) {
- state->rejected = true;
- f->avail_cpus--;
- }
-
- state->online = false;
- state->busy = 0;
- f->online_cpus--;
- break;
- }
-
- if (f->online_cpus < apply_limits(f, f->need_cpus)
- && f->online_cpus < f->avail_cpus
- && action == CPU_DEAD)
- wake_up_hotplug_thread(f);
-
- return ret;
-}
-
-static struct notifier_block __refdata cpu_notifier = {
- .notifier_call = cpu_callback,
-};
-
-/* ============================ init code ============================== */
-
-#define HOTPLUG_THREAD_NICE_VAL -7
-static int group_init(struct cpumask *mask)
-{
- struct device *dev;
- unsigned int first_cpu = cpumask_first(mask);
- struct cpu_data *f = &per_cpu(cpu_state, first_cpu);
- struct cpu_data *state;
- unsigned int cpu;
-
- if (likely(f->inited))
- return 0;
-
- dev = core_ctl_find_cpu_device(first_cpu);
- if (!dev)
- return -ENODEV;
-
- pr_info("Creating CPU group %d\n", first_cpu);
-
- f->num_cpus = cpumask_weight(mask);
- if (f->num_cpus > MAX_CPUS_PER_GROUP) {
- pr_err("HW configuration not supported\n");
- return -EINVAL;
- }
- f->min_cpus = 1;
- f->max_cpus = f->num_cpus;
- f->need_cpus = f->num_cpus;
- f->avail_cpus = f->num_cpus;
- f->offline_delay_ms = 100;
- f->task_thres = UINT_MAX;
- f->nrrun = f->num_cpus;
- INIT_LIST_HEAD(&f->lru);
- INIT_LIST_HEAD(&f->pending_lru);
- init_timer(&f->timer);
- spin_lock_init(&f->pending_lock);
- f->timer.function = core_ctl_timer_func;
- f->timer.data = first_cpu;
-
- for_each_cpu(cpu, mask) {
- pr_info("Init CPU%u state\n", cpu);
-
- state = &per_cpu(cpu_state, cpu);
- state->cpu = cpu;
- state->first_cpu = first_cpu;
-
- if (cpu_online(cpu)) {
- f->online_cpus++;
- state->online = true;
- }
-
- list_add_tail(&state->sib, &f->lru);
- INIT_LIST_HEAD(&state->pending_sib);
- }
-
- f->hotplug_thread = kthread_run(try_hotplug, (void *) f,
- "core_ctl/%d", first_cpu);
- set_user_nice(f->hotplug_thread, HOTPLUG_THREAD_NICE_VAL);
-
- for_each_cpu(cpu, mask) {
- state = &per_cpu(cpu_state, cpu);
- state->inited = true;
- }
-
- kobject_init(&f->kobj, &ktype_core_ctl);
- return kobject_add(&f->kobj, &dev->kobj, "core_ctl");
-}
-
-static int cpufreq_policy_cb(struct notifier_block *nb, unsigned long val,
- void *data)
-{
- struct cpufreq_policy *policy = data;
-
- switch (val) {
- case CPUFREQ_CREATE_POLICY:
- group_init(policy->related_cpus);
- break;
- }
-
- return NOTIFY_OK;
-}
-
-static struct notifier_block cpufreq_pol_nb = {
- .notifier_call = cpufreq_policy_cb,
-};
-
-static int cpufreq_gov_cb(struct notifier_block *nb, unsigned long val,
- void *data)
-{
- struct cpufreq_govinfo *info = data;
-
- switch (val) {
- case CPUFREQ_LOAD_CHANGE:
- core_ctl_set_busy(info->cpu, info->load);
- break;
- }
-
- return NOTIFY_OK;
-}
-
-static struct notifier_block cpufreq_gov_nb = {
- .notifier_call = cpufreq_gov_cb,
-};
-
-static int __init core_ctl_init(void)
-{
- struct cpufreq_policy *policy;
- unsigned int cpu;
-
- register_cpu_notifier(&cpu_notifier);
- cpufreq_register_notifier(&cpufreq_pol_nb, CPUFREQ_POLICY_NOTIFIER);
- cpufreq_register_notifier(&cpufreq_gov_nb, CPUFREQ_GOVINFO_NOTIFIER);
- init_timer_deferrable(&rq_avg_timer);
- rq_avg_timer.function = rq_avg_timer_func;
-
- core_ctl_block_hotplug();
- for_each_online_cpu(cpu) {
- policy = core_ctl_get_policy(cpu);
- if (policy) {
- group_init(policy->related_cpus);
- core_ctl_put_policy(policy);
- }
- }
- core_ctl_unblock_hotplug();
- mod_timer(&rq_avg_timer, round_to_nw_start());
- return 0;
-}
-
-static void __exit core_ctl_exit(void)
-{
- int cpu;
- struct cpu_data *pcpu;
-
- unregister_cpu_notifier(&cpu_notifier);
- cpufreq_unregister_notifier(&cpufreq_pol_nb, CPUFREQ_POLICY_NOTIFIER);
- cpufreq_unregister_notifier(&cpufreq_gov_nb, CPUFREQ_GOVINFO_NOTIFIER);
- del_timer_sync(&rq_avg_timer);
-
- for_each_possible_cpu(cpu) {
- pcpu = &per_cpu(cpu_state, cpu);
- if (pcpu->inited && cpu == pcpu->first_cpu) {
- pcpu->inited = false;
- del_timer_sync(&pcpu->timer);
- kthread_stop(pcpu->hotplug_thread);
- kobject_put(&pcpu->kobj);
- }
- pcpu->inited = false;
- }
-}
-
-module_init(core_ctl_init);
-module_exit(core_ctl_exit);
-
-MODULE_DESCRIPTION("MSM Core Control Driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/soc/qcom/core_ctl_helper.c b/drivers/soc/qcom/core_ctl_helper.c
deleted file mode 100644
index 3b25d9811cf..00000000000
--- a/drivers/soc/qcom/core_ctl_helper.c
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (c) 2014, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/cpu.h>
-#include <linux/cpufreq.h>
-#include <linux/ktime.h>
-#include <linux/hrtimer.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <soc/qcom/core_ctl.h>
-
-void core_ctl_block_hotplug(void)
-{
- get_online_cpus();
-}
-EXPORT_SYMBOL(core_ctl_block_hotplug);
-
-void core_ctl_unblock_hotplug(void)
-{
- put_online_cpus();
-}
-EXPORT_SYMBOL(core_ctl_unblock_hotplug);
-
-s64 core_ctl_get_time(void)
-{
- return ktime_to_ms(ktime_get());
-}
-EXPORT_SYMBOL(core_ctl_get_time);
-
-struct cpufreq_policy *core_ctl_get_policy(int cpu)
-{
- return cpufreq_cpu_get(cpu);
-}
-EXPORT_SYMBOL(core_ctl_get_policy);
-
-void core_ctl_put_policy(struct cpufreq_policy *policy)
-{
- cpufreq_cpu_put(policy);
-}
-EXPORT_SYMBOL(core_ctl_put_policy);
-
-struct device *core_ctl_find_cpu_device(unsigned cpu)
-{
- return get_cpu_device(cpu);
-}
-EXPORT_SYMBOL(core_ctl_find_cpu_device);
-
-int __ref core_ctl_online_core(unsigned int cpu)
-{
- return cpu_up(cpu);
-}
-EXPORT_SYMBOL(core_ctl_online_core);
diff --git a/drivers/soc/qcom/peripheral-loader.c b/drivers/soc/qcom/peripheral-loader.c
index 085345454ca..c8006ca3792 100644
--- a/drivers/soc/qcom/peripheral-loader.c
+++ b/drivers/soc/qcom/peripheral-loader.c
@@ -381,6 +381,8 @@ static int pil_alloc_region(struct pil_priv *priv, phys_addr_t min_addr,
if (region == NULL) {
pil_err(priv->desc, "Failed to allocate relocatable region of size %zx\n",
size);
+ priv->region_start = 0;
+ priv->region_end = 0;
return -ENOMEM;
}
diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c
index 7f699c6d2aa..cd7c27bbfa2 100644
--- a/drivers/soc/qcom/socinfo.c
+++ b/drivers/soc/qcom/socinfo.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009-2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2015,2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -52,6 +52,7 @@
#define SMEM_IMAGE_VERSION_OEM_OFFSET 96
#define SMEM_IMAGE_VERSION_PARTITION_APPS 10
+static DECLARE_RWSEM(current_image_rwsem);
enum {
HW_PLATFORM_UNKNOWN = 0,
HW_PLATFORM_SURF = 1,
@@ -800,7 +801,9 @@ msm_get_image_version(struct device *dev,
__func__);
return snprintf(buf, SMEM_IMAGE_VERSION_NAME_SIZE, "Unknown");
}
+ down_read(&current_image_rwsem);
string_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE;
+ up_read(&current_image_rwsem);
return snprintf(buf, SMEM_IMAGE_VERSION_NAME_SIZE, "%-.75s\n",
string_address);
}
@@ -813,15 +816,20 @@ msm_set_image_version(struct device *dev,
{
char *store_address;
- if (current_image != SMEM_IMAGE_VERSION_PARTITION_APPS)
+ down_read(&current_image_rwsem);
+ if (current_image != SMEM_IMAGE_VERSION_PARTITION_APPS) {
+ up_read(&current_image_rwsem);
return count;
+ }
store_address = socinfo_get_image_version_base_address();
if (IS_ERR_OR_NULL(store_address)) {
pr_err("%s : Failed to get image version base address",
__func__);
+ up_read(&current_image_rwsem);
return count;
}
store_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE;
+ up_read(&current_image_rwsem);
snprintf(store_address, SMEM_IMAGE_VERSION_NAME_SIZE, "%-.75s", buf);
return count;
}
@@ -840,7 +848,9 @@ msm_get_image_variant(struct device *dev,
return snprintf(buf, SMEM_IMAGE_VERSION_VARIANT_SIZE,
"Unknown");
}
+ down_read(&current_image_rwsem);
string_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE;
+ up_read(&current_image_rwsem);
string_address += SMEM_IMAGE_VERSION_VARIANT_OFFSET;
return snprintf(buf, SMEM_IMAGE_VERSION_VARIANT_SIZE, "%-.20s\n",
string_address);
@@ -854,15 +864,20 @@ msm_set_image_variant(struct device *dev,
{
char *store_address;
- if (current_image != SMEM_IMAGE_VERSION_PARTITION_APPS)
+ down_read(&current_image_rwsem);
+ if (current_image != SMEM_IMAGE_VERSION_PARTITION_APPS) {
+ up_read(&current_image_rwsem);
return count;
+ }
store_address = socinfo_get_image_version_base_address();
if (IS_ERR_OR_NULL(store_address)) {
pr_err("%s : Failed to get image version base address",
__func__);
+ up_read(&current_image_rwsem);
return count;
}
store_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE;
+ up_read(&current_image_rwsem);
store_address += SMEM_IMAGE_VERSION_VARIANT_OFFSET;
snprintf(store_address, SMEM_IMAGE_VERSION_VARIANT_SIZE, "%-.20s", buf);
return count;
@@ -881,7 +896,9 @@ msm_get_image_crm_version(struct device *dev,
__func__);
return snprintf(buf, SMEM_IMAGE_VERSION_OEM_SIZE, "Unknown");
}
+ down_read(&current_image_rwsem);
string_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE;
+ up_read(&current_image_rwsem);
string_address += SMEM_IMAGE_VERSION_OEM_OFFSET;
return snprintf(buf, SMEM_IMAGE_VERSION_OEM_SIZE, "%-.32s\n",
string_address);
@@ -895,15 +912,20 @@ msm_set_image_crm_version(struct device *dev,
{
char *store_address;
- if (current_image != SMEM_IMAGE_VERSION_PARTITION_APPS)
+ down_read(&current_image_rwsem);
+ if (current_image != SMEM_IMAGE_VERSION_PARTITION_APPS) {
+ up_read(&current_image_rwsem);
return count;
+ }
store_address = socinfo_get_image_version_base_address();
if (IS_ERR_OR_NULL(store_address)) {
pr_err("%s : Failed to get image version base address",
__func__);
+ up_read(&current_image_rwsem);
return count;
}
store_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE;
+ up_read(&current_image_rwsem);
store_address += SMEM_IMAGE_VERSION_OEM_OFFSET;
snprintf(store_address, SMEM_IMAGE_VERSION_OEM_SIZE, "%-.32s", buf);
return count;
@@ -914,8 +936,14 @@ msm_get_image_number(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- return snprintf(buf, PAGE_SIZE, "%d\n",
+ int ret;
+
+ down_read(&current_image_rwsem);
+ ret = snprintf(buf, PAGE_SIZE, "%d\n",
current_image);
+ up_read(&current_image_rwsem);
+ return ret;
+
}
static ssize_t
@@ -927,10 +955,12 @@ msm_select_image(struct device *dev, struct device_attribute *attr,
ret = kstrtoint(buf, 10, &digit);
if (ret)
return ret;
+ down_write(&current_image_rwsem);
if (0 <= digit && digit < SMEM_IMAGE_VERSION_BLOCKS_COUNT)
current_image = digit;
else
current_image = 0;
+ up_write(&current_image_rwsem);
return count;
}
diff --git a/drivers/staging/prima/CORE/DXE/src/wlan_qct_dxe.c b/drivers/staging/prima/CORE/DXE/src/wlan_qct_dxe.c
index c7f7235b0a8..de64b93c89e 100644
--- a/drivers/staging/prima/CORE/DXE/src/wlan_qct_dxe.c
+++ b/drivers/staging/prima/CORE/DXE/src/wlan_qct_dxe.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@@ -3445,6 +3445,12 @@ static wpt_status dxeTXPushFrame
//HDXE_ASSERT(0);
}
+ if(wpalIsArpPkt(palPacket))
+ {
+ HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
+ "%s :ARP packet", __func__);
+ }
+
/* Everything is ready
* Trigger to start DMA */
status = wpalWriteRegister(channelEntry->channelRegister.chDXECtrlRegAddr,
@@ -3695,6 +3701,14 @@ static wpt_status dxeTXCompFrame
}
return status;
}
+
+ if(wpalIsArpPkt(currentCtrlBlk->xfrFrame))
+ {
+ HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
+ "%s :ARP packet DMA-ed ", __func__);
+ wpalUpdateTXArpFWdeliveredStats();
+ }
+
hostCtxt->txCompCB(hostCtxt->clientCtxt,
currentCtrlBlk->xfrFrame,
eWLAN_PAL_STATUS_SUCCESS);
diff --git a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg80211.h b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg80211.h
index f00390dcc22..d1ca157f87e 100644
--- a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg80211.h
+++ b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg80211.h
@@ -197,6 +197,11 @@ enum qca_nl80211_vendor_subcmds {
QCA_NL80211_VENDOR_SUBCMD_LINK_PROPERTIES = 101,
QCA_NL80211_VENDOR_SUBCMD_SETBAND = 105,
+
+ /* Start / Stop the NUD stats collections */
+ QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_SET = 149,
+ /* Get the NUD stats, represented by the enum qca_attr_nud_stats_get */
+ QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET = 150,
};
enum qca_nl80211_vendor_subcmds_index {
@@ -232,6 +237,63 @@ enum qca_nl80211_vendor_subcmds_index {
QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI_INDEX,
QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_LOST_INDEX,
+ QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET_INDEX,
+};
+
+/**
+ * qca_wlan_vendor_attr_nud_stats_set: attribute to vendor subcmd
+ * QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_SET. This carry the requisite
+ * information to start / stop the NUD stats collection.
+ */
+enum qca_attr_nud_stats_set {
+ QCA_ATTR_NUD_STATS_SET_INVALID = 0,
+
+ /* Flag to Start / Stop the NUD stats collection
+ * Start - If included , Stop - If not included
+ */
+ QCA_ATTR_NUD_STATS_SET_START = 1,
+ /* IPv4 address of Default Gateway (in network byte order) */
+ QCA_ATTR_NUD_STATS_GW_IPV4 = 2,
+
+ /* keep last */
+ QCA_ATTR_NUD_STATS_SET_LAST,
+ QCA_ATTR_NUD_STATS_SET_MAX =
+ QCA_ATTR_NUD_STATS_SET_LAST - 1,
+};
+
+/**
+ * qca_attr_nud_stats_get: attribute to vendor subcmd
+ * QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET. This carry the requisite
+ * NUD stats collected when queried.
+ */
+enum qca_attr_nud_stats_get {
+ QCA_ATTR_NUD_STATS_GET_INVALID = 0,
+ /* ARP Request Count from net dev */
+ QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_FROM_NETDEV = 1,
+ /* ARP Request Count sent to lower MAC from upper MAC */
+ QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TO_LOWER_MAC = 2,
+ /* ARP Request Count received by lower MAC from upper MAC */
+ QCA_ATTR_NUD_STATS_ARP_REQ_RX_COUNT_BY_LOWER_MAC = 3,
+ /* ARP Request Count successfully transmitted by the device */
+ QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TX_SUCCESS = 4,
+ /* ARP Response Count received by lower MAC */
+ QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_LOWER_MAC = 5,
+ /* ARP Response Count received by upper MAC */
+ QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_UPPER_MAC = 6,
+ /* ARP Response Count delivered to netdev */
+ QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_TO_NETDEV = 7,
+ /* ARP Response Count delivered to netdev */
+ QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_OUT_OF_ORDER_DROP = 8,
+ /*
+ * Flag indicating if the Stations Link to AP is active.
+ * Active Link - If exists, Inactive link - If not included
+ */
+ QCA_ATTR_NUD_STATS_AP_LINK_ACTIVE= 9,
+ QCA_ATTR_NUD_STATS_AP_LINK_DAD= 10,
+ /* keep last */
+ QCA_ATTR_NUD_STATS_GET_LAST,
+ QCA_ATTR_NUD_STATS_GET_MAX =
+ QCA_ATTR_NUD_STATS_GET_LAST - 1,
};
enum qca_wlan_vendor_attr
diff --git a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h
index 610c6f88e54..dd20161009f 100644
--- a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h
+++ b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h
@@ -101,6 +101,7 @@
#define SOFTAP_BSS_STARTED (4)
#define DEVICE_IFACE_OPENED (5)
#define TDLS_INIT_DONE (6)
+#define SOFTAP_INIT_DONE (7)
/** Maximum time(ms)to wait for disconnect to complete **/
#define WLAN_WAIT_TIME_DISCONNECT 5000
@@ -376,6 +377,35 @@ typedef struct hdd_pmf_stats_s
} hdd_pmf_stats_t;
#endif
+typedef enum
+{
+ HDD_TX_FRAME_IN_NOT_ASSOCIATED_STATE = 0,
+ HDD_VOS_PACKET_RETURNED_BY_VOSS_IS_NULL,
+ HDD_WLANTL_STAPKTPENDING_RETURNED_ERROR_CODE,
+ HDD_INSERT_TX_QUEUE_FAILED,
+ HDD_FAILED_TO_SIGNAL_TL,
+ HDD_ERROR_ATTACHING_SKB,
+ HDD_FAILURE_EXTRACTING_SKB_FROM_VOS_PKT,
+ HDD_FAILURE_WALKING_PACKET_CHAIN,
+ HDD_STA_RX_ARP_PACKET_REFUSED_IN_NET_STACK
+} HDD_PACKET_DROP_CAUSE;
+
+typedef struct hdd_arp_stats_s
+{
+ uint16 tx_arp_req_count;
+ uint16 rx_arp_rsp_count;
+ uint16 txDropped;
+ uint16 rxDropped;
+ uint16 rxDelivered;
+ uint16 rxRefused;
+ uint16 tx_host_fw_sent;
+ uint16 rx_host_drop_reorder;
+ uint16_t tx_fw_cnt;
+ uint16_t rx_fw_cnt;
+ uint16_t tx_ack_cnt;
+ HDD_PACKET_DROP_CAUSE reason;
+} hdd_arp_stats_t;
+
typedef struct hdd_stats_s
{
tCsrSummaryStatsInfo summary_stat;
@@ -386,6 +416,7 @@ typedef struct hdd_stats_s
tCsrPerStaStatsInfo perStaStats;
hdd_tx_rx_stats_t hddTxRxStats;
hdd_chip_reset_stats_t hddChipResetStats;
+ hdd_arp_stats_t hddArpStats;
#ifdef WLAN_FEATURE_11W
hdd_pmf_stats_t hddPmfStats;
#endif
@@ -1216,6 +1247,9 @@ struct hdd_adapter_s
/* Currently used antenna Index*/
int antennaIndex;
+ bool nud_set_arp_stats;
+ bool con_status;
+ bool dad;
};
#define WLAN_HDD_GET_STATION_CTX_PTR(pAdapter) (&(pAdapter)->sessionCtx.station)
@@ -1273,6 +1307,10 @@ typedef struct
#define WLAN_WAIT_TIME_LL_STATS 800
+#define WLAN_WAIT_TIME_NUD_STATS 800
+#define WLAN_NUD_STATS_LEN 800
+#define WLAN_NUD_STATS_ARP_PKT_TYPE 1
+
/* FW memory dump feature
@TODO : Move this code to a separate file later */
#define PROCFS_MEMDUMP_DIR "debug"
@@ -1320,6 +1358,15 @@ struct hdd_ll_stats_context {
struct completion response_event;
};
#endif /* End of WLAN_FEATURE_LINK_LAYER_STATS */
+
+/**
+ * struct hdd_nud_stats_context - hdd NUD stats context
+ *
+ * @response_event: NUD stats request wait event
+ */
+struct hdd_nud_stats_context {
+ struct completion response_event;
+};
#ifdef WLAN_FEATURE_EXTSCAN
/**
* struct hdd_ext_scan_context - hdd ext scan context
@@ -1605,6 +1652,7 @@ struct hdd_context_s
#ifdef WLAN_FEATURE_LINK_LAYER_STATS
struct hdd_ll_stats_context ll_stats_context;
#endif /* End of WLAN_FEATURE_LINK_LAYER_STATS */
+ struct hdd_nud_stats_context nud_stats_context;
#ifdef WLAN_FEATURE_EXTSCAN
struct hdd_ext_scan_context ext_scan_context;
@@ -1638,6 +1686,8 @@ struct hdd_context_s
v_U8_t last_scan_reject_session_id;
scan_reject_states last_scan_reject_reason;
v_TIME_t last_scan_reject_timestamp;
+
+ uint32_t track_arp_ip;
};
typedef enum {
@@ -1955,6 +2005,19 @@ static inline void hdd_init_ll_stat_ctx(void)
return;
}
#endif /* WLAN_FEATURE_LINK_LAYER_STATS */
+
+/**
+ * hdd_init_nud_stats_ctx() - initialize NUD stats context
+ * @hdd_ctx: Pointer to hdd context
+ *
+ * Return: none
+ */
+static inline void hdd_init_nud_stats_ctx(hdd_context_t *hdd_ctx)
+{
+ init_completion(&hdd_ctx->nud_stats_context.response_event);
+ return;
+}
+
void hdd_initialize_adapter_common(hdd_adapter_t *pAdapter);
void hdd_wlan_free_wiphy_channels(struct wiphy *wiphy);
void wlan_hdd_init_deinit_defer_scan_context(scan_context_t *scan_ctx);
diff --git a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_wmm.h b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_wmm.h
index ca4db65c53f..4e1eb237b83 100644
--- a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_wmm.h
+++ b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_wmm.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@@ -415,4 +415,12 @@ VOS_STATUS hdd_wmm_adapter_clear( hdd_adapter_t *pAdapter );
===========================================================================*/
void hdd_log_ip_addr(struct sk_buff *skb);
+/**============================================================================
+ @brief hdd_get_arp_src_ip() - Function to get ARP src IP addr
+ @param pAdapter : [in] pointer to os packet
+
+ @return : IP address
+ ===========================================================================*/
+uint32_t hdd_get_arp_src_ip(struct sk_buff *skb);
+
#endif /* #ifndef _WLAN_HDD_WMM_H */
diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_assoc.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_assoc.c
index 4fc44c2557a..b7c935de763 100644
--- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_assoc.c
+++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_assoc.c
@@ -1258,6 +1258,7 @@ static eHalStatus hdd_DisConnectHandler( hdd_adapter_t *pAdapter, tCsrRoamInfo *
pAdapter->hdd_stats.hddTxRxStats.txMcast[WLANTL_AC_BE] = 0;
pAdapter->hdd_stats.hddTxRxStats.txMcast[WLANTL_AC_BK] = 0;
#endif /* WLAN_FEATURE_LINK_LAYER_STATS */
+ pAdapter->dad = false;
// Clear saved connection information in HDD
hdd_connRemoveConnectInfo( pHddStaCtx );
diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c
index 4e2f02bd701..66c732e235c 100644
--- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c
+++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c
@@ -7464,6 +7464,455 @@ static int wlan_hdd_cfg80211_wifi_configuration_set(struct wiphy *wiphy,
return ret;
}
+
+/*
+ * define short names for the global vendor params
+ * used by wlan_hdd_cfg80211_setarp_stats_cmd()
+ */
+#define STATS_SET_INVALID \
+ QCA_ATTR_NUD_STATS_SET_INVALID
+#define STATS_SET_START \
+ QCA_ATTR_NUD_STATS_SET_START
+#define STATS_GW_IPV4 \
+ QCA_ATTR_NUD_STATS_GW_IPV4
+#define STATS_SET_MAX \
+ QCA_ATTR_NUD_STATS_SET_MAX
+
+const struct nla_policy
+qca_wlan_vendor_set_nud_stats[STATS_SET_MAX +1] =
+{
+ [STATS_SET_START] = {.type = NLA_FLAG },
+ [STATS_GW_IPV4] = {.type = NLA_U32 },
+};
+
+/**
+ * hdd_test_con_alive() - check connection alive
+ * @adapter: pointer to adapter
+ *
+ * Return: true if SME command is sent of false otherwise
+ */
+static bool hdd_test_con_alive(hdd_adapter_t *adapter)
+{
+ hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
+
+ if (eHAL_STATUS_SUCCESS != sme_test_con_alive(hdd_ctx->hHal)) {
+ hddLog(LOGE, FL("could not send ADDBA"));
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * hdd_set_nud_stats_cb() - hdd callback api to get status
+ * @data: pointer to adapter
+ * @rsp: status
+ *
+ * Return: None
+ */
+static void hdd_set_nud_stats_cb(void *data, VOS_STATUS rsp)
+{
+
+ hdd_adapter_t *adapter = (hdd_adapter_t *)data;
+
+ if (NULL == adapter)
+ return;
+
+ if (VOS_STATUS_SUCCESS == rsp) {
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
+ "%s success received STATS_SET_START", __func__);
+ if (adapter->nud_set_arp_stats)
+ hdd_test_con_alive(adapter);
+ } else {
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ "%s STATS_SET_START Failed!!", __func__);
+ }
+ return;
+}
+
+/**
+ * __wlan_hdd_cfg80211_set_nud_stats() - set arp stats command to firmware
+ * @wiphy: pointer to wireless wiphy structure.
+ * @wdev: pointer to wireless_dev structure.
+ * @data: pointer to apfind configuration data.
+ * @data_len: the length in byte of apfind data.
+ *
+ * This is called when wlan driver needs to send arp stats to
+ * firmware.
+ *
+ * Return: An error code or 0 on success.
+ */
+static int __wlan_hdd_cfg80211_set_nud_stats(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct nlattr *tb[STATS_SET_MAX + 1];
+ struct net_device *dev = wdev->netdev;
+ hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
+ hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
+ v_CONTEXT_t pVosContext = (WLAN_HDD_GET_CTX(adapter))->pvosContext;
+ setArpStatsParams arp_stats_params;
+ int err = 0;
+
+ ENTER();
+
+ err = wlan_hdd_validate_context(hdd_ctx);
+ if (0 != err)
+ return err;
+
+ if (!sme_IsFeatureSupportedByFW(NUD_DEBUG)) {
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ "%s NUD_DEBUG feature not supported by firmware!!", __func__);
+ return -EINVAL;
+ }
+
+ err = nla_parse(tb, STATS_SET_MAX, data, data_len,
+ qca_wlan_vendor_set_nud_stats);
+ if (err)
+ {
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ "%s STATS_SET_START ATTR", __func__);
+ return err;
+ }
+
+ if (tb[STATS_SET_START])
+ {
+ if (!tb[STATS_GW_IPV4]) {
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ "%s STATS_SET_START CMD", __func__);
+ return -EINVAL;
+ }
+ arp_stats_params.flag = true;
+ adapter->nud_set_arp_stats = true;
+ arp_stats_params.ip_addr = nla_get_u32(tb[STATS_GW_IPV4]);
+ } else {
+ arp_stats_params.flag = false;
+ adapter->nud_set_arp_stats = false;
+ }
+ if (!arp_stats_params.flag) {
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
+ "%s STATS_SET_START Cleared!!", __func__);
+ hdd_ctx->track_arp_ip = 0;
+ vos_mem_zero(&adapter->hdd_stats.hddArpStats, sizeof(adapter->hdd_stats.hddArpStats));
+ }
+
+ arp_stats_params.pkt_type = 1; // ARP packet type
+
+ if (arp_stats_params.flag) {
+ hdd_ctx->track_arp_ip = arp_stats_params.ip_addr;
+ WLANTL_SetARPFWDatapath(pVosContext, true);
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
+ "%s Set FW in data path for ARP with tgt IP :%d",
+ __func__, hdd_ctx->track_arp_ip);
+ }
+ else {
+ WLANTL_SetARPFWDatapath(pVosContext, false);
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
+ "%s Remove FW from data path", __func__);
+ }
+
+ arp_stats_params.rsp_cb_fn = hdd_set_nud_stats_cb;
+ arp_stats_params.data_ctx = adapter;
+
+ if (eHAL_STATUS_SUCCESS !=
+ sme_set_nud_debug_stats(hdd_ctx->hHal, &arp_stats_params)) {
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ "%s STATS_SET_START CMD Failed!!", __func__);
+ return -EINVAL;
+ }
+
+ EXIT();
+
+ return err;
+}
+
+/**
+ * wlan_hdd_cfg80211_set_nud_stats() - set arp stats command to firmware
+ * @wiphy: pointer to wireless wiphy structure.
+ * @wdev: pointer to wireless_dev structure.
+ * @data: pointer to apfind configuration data.
+ * @data_len: the length in byte of apfind data.
+ *
+ * This is called when wlan driver needs to send arp stats to
+ * firmware.
+ *
+ * Return: An error code or 0 on success.
+ */
+static int wlan_hdd_cfg80211_set_nud_stats(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ int ret;
+
+ vos_ssr_protect(__func__);
+ ret = __wlan_hdd_cfg80211_set_nud_stats(wiphy, wdev, data, data_len);
+ vos_ssr_unprotect(__func__);
+
+ return ret;
+}
+#undef STATS_SET_INVALID
+#undef STATS_SET_START
+#undef STATS_GW_IPV4
+#undef STATS_SET_MAX
+
+/*
+ * define short names for the global vendor params
+ * used by wlan_hdd_cfg80211_setarp_stats_cmd()
+ */
+#define STATS_GET_INVALID \
+ QCA_ATTR_NUD_STATS_SET_INVALID
+#define COUNT_FROM_NETDEV \
+ QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_FROM_NETDEV
+#define COUNT_TO_LOWER_MAC \
+ QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TO_LOWER_MAC
+#define RX_COUNT_BY_LOWER_MAC \
+ QCA_ATTR_NUD_STATS_ARP_REQ_RX_COUNT_BY_LOWER_MAC
+#define COUNT_TX_SUCCESS \
+ QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TX_SUCCESS
+#define RSP_RX_COUNT_BY_LOWER_MAC \
+ QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_LOWER_MAC
+#define RSP_RX_COUNT_BY_UPPER_MAC \
+ QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_UPPER_MAC
+#define RSP_COUNT_TO_NETDEV \
+ QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_TO_NETDEV
+#define RSP_COUNT_OUT_OF_ORDER_DROP \
+ QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_OUT_OF_ORDER_DROP
+#define AP_LINK_ACTIVE \
+ QCA_ATTR_NUD_STATS_AP_LINK_ACTIVE
+#define AP_LINK_DAD \
+ QCA_ATTR_NUD_STATS_AP_LINK_DAD
+#define STATS_GET_MAX \
+ QCA_ATTR_NUD_STATS_GET_MAX
+
+const struct nla_policy
+qca_wlan_vendor_get_nud_stats[STATS_GET_MAX +1] =
+{
+ [COUNT_FROM_NETDEV] = {.type = NLA_U16 },
+ [COUNT_TO_LOWER_MAC] = {.type = NLA_U16 },
+ [RX_COUNT_BY_LOWER_MAC] = {.type = NLA_U16 },
+ [COUNT_TX_SUCCESS] = {.type = NLA_U16 },
+ [RSP_RX_COUNT_BY_LOWER_MAC] = {.type = NLA_U16 },
+ [RSP_RX_COUNT_BY_UPPER_MAC] = {.type = NLA_U16 },
+ [RSP_COUNT_TO_NETDEV] = {.type = NLA_U16 },
+ [RSP_COUNT_OUT_OF_ORDER_DROP] = {.type = NLA_U16 },
+ [AP_LINK_ACTIVE] = {.type = NLA_FLAG },
+ [AP_LINK_DAD] = {.type = NLA_FLAG },
+};
+
+/**
+ * hdd_con_alive_cb() - Call back to get the connection status
+ * @context: pointer to adapter
+ *
+ * Return: None
+ */
+static void hdd_con_alive_cb(void *context, bool status)
+{
+ hdd_adapter_t *adapter = (hdd_adapter_t *)context;
+ adapter->con_status = status;
+}
+
+/**
+ * hdd_get_con_alive() - get the connection status
+ * @adapter: pointer to adapter
+ *
+ * Return: true if SME command is sent of false otherwise
+ */
+static bool hdd_get_con_alive(hdd_adapter_t *adapter)
+{
+ hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
+ getConStatusParams conStatusParams;
+
+ conStatusParams.rsp_cb_fn = hdd_con_alive_cb;
+ conStatusParams.data_ctx = adapter;
+
+ if (eHAL_STATUS_SUCCESS != sme_get_con_alive(hdd_ctx->hHal,
+ &conStatusParams))
+ {
+ hddLog(LOGE, FL("could not get connection status"));
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * hdd_con_test_DELBA() - delete the BA session
+ * @adapter: pointer to adapter
+ *
+ * Return: true if SME command is sent of false otherwise
+ */
+static bool hdd_con_test_DELBA(hdd_adapter_t *adapter)
+{
+ hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
+ hdd_station_ctx_t *pHddStaCtx = &adapter->sessionCtx.station;
+ uint8_t sta_id = pHddStaCtx->conn_info.staId[0];
+
+ ENTER();
+
+ if (eHAL_STATUS_SUCCESS != sme_test_con_delba((hdd_ctx->hHal), sta_id,
+ adapter->sessionId)) {
+ hddLog(LOGE, FL("could not send DELBA "));
+ return false;
+ }
+
+ return true;
+}
+
+static void hdd_get_nud_stats_cb(void *data, rsp_stats *rsp)
+{
+
+ hdd_adapter_t *adapter = (hdd_adapter_t *)data;
+ hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
+ struct hdd_nud_stats_context *context;
+ int status;
+
+ ENTER();
+
+ if (NULL == adapter)
+ return;
+
+ status = wlan_hdd_validate_context(hdd_ctx);
+ if (0 != status) {
+ return;
+ }
+
+ if (!rsp) {
+ hddLog(LOGE, FL("data is null"));
+ return;
+ }
+
+ adapter->hdd_stats.hddArpStats.tx_fw_cnt = rsp->tx_fw_cnt;
+ adapter->hdd_stats.hddArpStats.rx_fw_cnt = rsp->rx_fw_cnt;
+ adapter->hdd_stats.hddArpStats.tx_ack_cnt = rsp->tx_ack_cnt;
+ adapter->dad |= rsp->dad;
+
+ spin_lock(&hdd_context_lock);
+ context = &hdd_ctx->nud_stats_context;
+ complete(&context->response_event);
+ spin_unlock(&hdd_context_lock);
+
+ return;
+}
+static int __wlan_hdd_cfg80211_get_nud_stats(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ int err = 0;
+ unsigned long rc;
+ struct hdd_nud_stats_context *context;
+ struct net_device *dev = wdev->netdev;
+ hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
+ hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
+ getArpStatsParams arp_stats_params;
+ struct sk_buff *skb;
+
+ ENTER();
+
+ err = wlan_hdd_validate_context(hdd_ctx);
+ if (0 != err)
+ return err;
+
+ hdd_get_con_alive(adapter);
+
+ arp_stats_params.pkt_type = WLAN_NUD_STATS_ARP_PKT_TYPE;
+ arp_stats_params.get_rsp_cb_fn = hdd_get_nud_stats_cb;
+ arp_stats_params.data_ctx = adapter;
+
+ spin_lock(&hdd_context_lock);
+ context = &hdd_ctx->nud_stats_context;
+ INIT_COMPLETION(context->response_event);
+ spin_unlock(&hdd_context_lock);
+
+ if (!sme_IsFeatureSupportedByFW(NUD_DEBUG)) {
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ "%s NUD_DEBUG feature not supported by firmware!!", __func__);
+ return -EINVAL;
+ }
+
+ if (eHAL_STATUS_SUCCESS !=
+ sme_get_nud_debug_stats(hdd_ctx->hHal, &arp_stats_params)) {
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ "%s STATS_SET_START CMD Failed!!", __func__);
+ return -EINVAL;
+ }
+
+ rc = wait_for_completion_timeout(&context->response_event,
+ msecs_to_jiffies(WLAN_WAIT_TIME_NUD_STATS));
+ if (!rc)
+ {
+ hddLog(LOGE,
+ FL("Target response timed out request "));
+ return -ETIMEDOUT;
+ }
+
+ skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy,
+ WLAN_NUD_STATS_LEN);
+ if (!skb)
+ {
+ hddLog(VOS_TRACE_LEVEL_ERROR,
+ "%s: cfg80211_vendor_cmd_alloc_reply_skb failed",
+ __func__);
+ return -ENOMEM;
+ }
+
+ if (nla_put_u16(skb, COUNT_FROM_NETDEV,
+ adapter->hdd_stats.hddArpStats.tx_arp_req_count) ||
+ nla_put_u16(skb, COUNT_TO_LOWER_MAC,
+ adapter->hdd_stats.hddArpStats.tx_host_fw_sent) ||
+ nla_put_u16(skb, RX_COUNT_BY_LOWER_MAC,
+ adapter->hdd_stats.hddArpStats.tx_fw_cnt) ||
+ nla_put_u16(skb, COUNT_TX_SUCCESS,
+ adapter->hdd_stats.hddArpStats.tx_ack_cnt) ||
+ nla_put_u16(skb, RSP_RX_COUNT_BY_LOWER_MAC,
+ adapter->hdd_stats.hddArpStats.rx_fw_cnt) ||
+ nla_put_u16(skb, RSP_RX_COUNT_BY_UPPER_MAC,
+ adapter->hdd_stats.hddArpStats.rx_arp_rsp_count) ||
+ nla_put_u16(skb, RSP_COUNT_TO_NETDEV,
+ adapter->hdd_stats.hddArpStats.rxDelivered) ||
+ nla_put_u16(skb, RSP_COUNT_OUT_OF_ORDER_DROP,
+ adapter->hdd_stats.hddArpStats.rx_host_drop_reorder)) {
+ hddLog(LOGE, FL("nla put fail"));
+ kfree_skb(skb);
+ return -EINVAL;
+ }
+ if (adapter->con_status) {
+ nla_put_flag(skb, AP_LINK_ACTIVE);
+ adapter->con_status = false;
+ hdd_con_test_DELBA(adapter);
+ }
+ if (adapter->dad)
+ nla_put_flag(skb, AP_LINK_DAD);
+
+ hdd_ctx->track_arp_ip = 0;
+ cfg80211_vendor_cmd_reply(skb);
+ return err;
+}
+
+static int wlan_hdd_cfg80211_get_nud_stats(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ int ret;
+
+ vos_ssr_protect(__func__);
+ ret = __wlan_hdd_cfg80211_get_nud_stats(wiphy, wdev, data, data_len);
+ vos_ssr_unprotect(__func__);
+
+ return ret;
+}
+
+#undef QCA_ATTR_NUD_STATS_SET_INVALID
+#undef QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_FROM_NETDEV
+#undef QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TO_LOWER_MAC
+#undef QCA_ATTR_NUD_STATS_ARP_REQ_RX_COUNT_BY_LOWER_MAC
+#undef QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TX_SUCCESS
+#undef QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_LOWER_MAC
+#undef QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_UPPER_MAC
+#undef QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_TO_NETDEV
+#undef QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_OUT_OF_ORDER_DROP
+#undef QCA_ATTR_NUD_STATS_AP_LINK_ACTIVE
+#undef QCA_ATTR_NUD_STATS_GET_MAX
+
const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] =
{
{
@@ -7709,7 +8158,23 @@ const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] =
WIPHY_VENDOR_CMD_NEED_NETDEV |
WIPHY_VENDOR_CMD_NEED_RUNNING,
.doit = wlan_hdd_cfg80211_wifi_configuration_set
- }
+ },
+ {
+ .info.vendor_id = QCA_NL80211_VENDOR_ID,
+ .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_SET,
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+ WIPHY_VENDOR_CMD_NEED_NETDEV |
+ WIPHY_VENDOR_CMD_NEED_RUNNING,
+ .doit = wlan_hdd_cfg80211_set_nud_stats
+ },
+ {
+ .info.vendor_id = QCA_NL80211_VENDOR_ID,
+ .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET,
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+ WIPHY_VENDOR_CMD_NEED_NETDEV |
+ WIPHY_VENDOR_CMD_NEED_RUNNING,
+ .doit = wlan_hdd_cfg80211_get_nud_stats
+ },
};
/* vendor specific events */
@@ -7840,7 +8305,10 @@ struct nl80211_vendor_cmd_info wlan_hdd_cfg80211_vendor_events[] =
.vendor_id = QCA_NL80211_VENDOR_ID,
.subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_LOST
},
-
+ [QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET_INDEX] = {
+ .vendor_id = QCA_NL80211_VENDOR_ID,
+ .subcmd = QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET,
+ },
};
/*
@@ -9235,7 +9703,7 @@ static int wlan_hdd_cfg80211_start_bss(hdd_adapter_t *pHostapdAdapter,
eCsrAuthType RSNAuthType;
eCsrEncryptionType RSNEncryptType;
eCsrEncryptionType mcRSNEncryptType;
- int status = VOS_STATUS_SUCCESS;
+ int status = VOS_STATUS_SUCCESS, ret = 0;
tpWLAN_SAPEventCB pSapEventCallback;
hdd_hostapd_state_t *pHostapdState;
v_CONTEXT_t pVosContext = (WLAN_HDD_GET_CTX(pHostapdAdapter))->pvosContext;
@@ -9680,12 +10148,15 @@ static int wlan_hdd_cfg80211_start_bss(hdd_adapter_t *pHostapdAdapter,
}
pConfig->acsBandSwitchThreshold = iniConfig->acsBandSwitchThreshold;
+ set_bit(SOFTAP_INIT_DONE, &pHostapdAdapter->event_flags);
+
pSapEventCallback = hdd_hostapd_SAPEventCB;
if(WLANSAP_StartBss(pVosContext, pSapEventCallback, pConfig,
(v_PVOID_t)pHostapdAdapter->dev) != VOS_STATUS_SUCCESS)
{
hddLog(LOGE,FL("SAP Start Bss fail"));
- return -EINVAL;
+ ret = -EINVAL;
+ goto error;
}
hddLog(LOG1,
@@ -9728,6 +10199,9 @@ static int wlan_hdd_cfg80211_start_bss(hdd_adapter_t *pHostapdAdapter,
EXIT();
return 0;
+error:
+ clear_bit(SOFTAP_INIT_DONE, &pHostapdAdapter->event_flags);
+ return ret;
}
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,4,0))
@@ -10007,6 +10481,8 @@ static int __wlan_hdd_cfg80211_stop_ap (struct wiphy *wiphy,
// Reset WNI_CFG_PROBE_RSP Flags
wlan_hdd_reset_prob_rspies(pAdapter);
+ clear_bit(SOFTAP_INIT_DONE, &pAdapter->event_flags);
+
pAdapter->sessionCtx.ap.beacon = NULL;
kfree(old);
#ifdef WLAN_FEATURE_P2P_DEBUG
@@ -10086,6 +10562,8 @@ static int __wlan_hdd_cfg80211_start_ap(struct wiphy *wiphy,
return -ENODEV;
}
+ clear_bit(SOFTAP_INIT_DONE, &pAdapter->event_flags);
+
pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
status = wlan_hdd_validate_context(pHddCtx);
if (0 != status)
@@ -14681,6 +15159,11 @@ static int wlan_hdd_try_disconnect( hdd_adapter_t *pAdapter )
(eConnectionState_Connecting == pHddStaCtx->conn_info.connState) ||
(eConnectionState_IbssConnected == pHddStaCtx->conn_info.connState))
{
+ /* Indicate disconnect to SME so that in-progress connection or preauth
+ * can be aborted
+ */
+ sme_abortConnection(WLAN_HDD_GET_HAL_CTX(pAdapter),
+ pAdapter->sessionId);
spin_lock_bh(&pAdapter->lock_for_active_session);
if (eConnectionState_Associated == pHddStaCtx->conn_info.connState)
{
diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_early_suspend.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_early_suspend.c
index f7547fe5e9a..3817d5ca9bc 100644
--- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_early_suspend.c
+++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_early_suspend.c
@@ -2335,9 +2335,10 @@ static void hdd_ssr_restart_sap(hdd_context_t *hdd_ctx)
while (NULL != adapter_node && VOS_STATUS_SUCCESS == status) {
adapter = adapter_node->pAdapter;
if (adapter && adapter->device_mode == WLAN_HDD_SOFTAP) {
- hddLog(VOS_TRACE_LEVEL_INFO, FL("in sap mode %p"),
- adapter);
- wlan_hdd_start_sap(adapter);
+ if (test_bit(SOFTAP_INIT_DONE, &adapter->event_flags)) {
+ hddLog(VOS_TRACE_LEVEL_INFO, FL("Restart prev SAP session"));
+ wlan_hdd_start_sap(adapter);
+ }
}
status = hdd_get_next_adapter(hdd_ctx, adapter_node, &next);
adapter_node = next;
diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c
index 9d79eb2184c..0a38b2d48eb 100644
--- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c
+++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c
@@ -11801,6 +11801,7 @@ int hdd_wlan_startup(struct device *dev )
hdd_init_ll_stats_ctx(pHddCtx);
+ hdd_init_nud_stats_ctx(pHddCtx);
#ifdef CONFIG_ENABLE_LINUX_REG
init_completion(&pHddCtx->linux_reg_req);
diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_p2p.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_p2p.c
index 2e4852ce114..d2225a4f2a6 100644
--- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_p2p.c
+++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_p2p.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@@ -132,9 +132,8 @@ static void hdd_sendMgmtFrameOverMonitorIface( hdd_adapter_t *pMonAdapter,
tANI_U8* pbFrames,
tANI_U8 frameType );
-static v_BOOL_t hdd_p2p_is_action_type_rsp( const u8 *buf )
+static v_BOOL_t wlan_hdd_is_type_p2p_action( const u8 *buf )
{
- tActionFrmType actionFrmType;
const u8 *ouiPtr;
if ( buf[WLAN_HDD_PUBLIC_ACTION_FRAME_CATEGORY_OFFSET] !=
@@ -158,14 +157,23 @@ static v_BOOL_t hdd_p2p_is_action_type_rsp( const u8 *buf )
return VOS_FALSE;
}
- actionFrmType = buf[WLAN_HDD_PUBLIC_ACTION_FRAME_SUB_TYPE_OFFSET];
- if ( actionFrmType != WLAN_HDD_INVITATION_REQ &&
- actionFrmType != WLAN_HDD_GO_NEG_REQ &&
- actionFrmType != WLAN_HDD_DEV_DIS_REQ &&
- actionFrmType != WLAN_HDD_PROV_DIS_REQ )
- return VOS_TRUE;
- else
- return VOS_FALSE;
+ return VOS_TRUE;
+}
+
+static bool hdd_p2p_is_action_type_rsp( const u8 *buf )
+{
+ tActionFrmType actionFrmType;
+
+ if ( wlan_hdd_is_type_p2p_action(buf) )
+ {
+ actionFrmType = buf[WLAN_HDD_PUBLIC_ACTION_FRAME_SUB_TYPE_OFFSET];
+ if ( actionFrmType != WLAN_HDD_INVITATION_REQ &&
+ actionFrmType != WLAN_HDD_GO_NEG_REQ &&
+ actionFrmType != WLAN_HDD_DEV_DIS_REQ &&
+ actionFrmType != WLAN_HDD_PROV_DIS_REQ )
+ return VOS_TRUE;
+ }
+ return VOS_FALSE;
}
eHalStatus wlan_hdd_remain_on_channel_callback( tHalHandle hHal, void* pCtx,
@@ -1293,7 +1301,7 @@ int __wlan_hdd_mgmt_tx( struct wiphy *wiphy, struct net_device *dev,
if ((type == SIR_MAC_MGMT_FRAME) &&
(subType == SIR_MAC_MGMT_ACTION) &&
- (buf[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET] == WLAN_HDD_PUBLIC_ACTION_FRAME))
+ wlan_hdd_is_type_p2p_action(&buf[WLAN_HDD_PUBLIC_ACTION_FRAME_BODY_OFFSET]))
{
actionFrmType = buf[WLAN_HDD_PUBLIC_ACTION_FRAME_TYPE_OFFSET];
#ifdef WLAN_FEATURE_P2P_DEBUG
diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_tx_rx.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_tx_rx.c
index 3cae5479a19..a3a73db4367 100644
--- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_tx_rx.c
+++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_tx_rx.c
@@ -819,6 +819,7 @@ int __hdd_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
v_BOOL_t txSuspended = VOS_FALSE;
struct sk_buff *skb1;
+ v_BOOL_t arp_pkt;
if (NULL == pHddCtx) {
VOS_TRACE( VOS_MODULE_ID_HDD_DATA, VOS_TRACE_LEVEL_ERROR,
@@ -835,6 +836,17 @@ int __hdd_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_BUSY;
}
+ arp_pkt = vos_is_arp_pkt(skb, false);
+
+ if (arp_pkt)
+ {
+ if (pHddCtx->track_arp_ip && vos_check_arp_req_target_ip(skb, false)) {
+ ++pAdapter->hdd_stats.hddArpStats.tx_arp_req_count;
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
+ "%s :ARP packet received form net_dev", __func__);
+ }
+ }
+
//Get TL Q index corresponding to Qdisc queue index/AC.
qid = hdd_QdiscAcToTlAC[skb->queue_mapping];
ac = qid;
@@ -852,6 +864,15 @@ int __hdd_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
VOS_TRACE( VOS_MODULE_ID_HDD_DATA, VOS_TRACE_LEVEL_INFO,
FL("Tx frame in not associated state in %d context"),
pAdapter->device_mode);
+
+ if (arp_pkt)
+ {
+ ++pAdapter->hdd_stats.hddArpStats.txDropped;
+ pAdapter->hdd_stats.hddArpStats.reason = HDD_TX_FRAME_IN_NOT_ASSOCIATED_STATE;
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ "%s :Tx frame in not associated state, ARP packet Dropped ",
+ __func__);
+ }
++pAdapter->stats.tx_dropped;
++pAdapter->hdd_stats.hddTxRxStats.txXmitDropped;
++pAdapter->hdd_stats.hddTxRxStats.txXmitDroppedAC[qid];
@@ -895,6 +916,15 @@ int __hdd_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
VOS_TRACE( VOS_MODULE_ID_HDD_DATA, VOS_TRACE_LEVEL_ERROR,
"%s: WLANTL_STAPktPending() returned error code %d",
__func__, status);
+
+ if (arp_pkt)
+ {
+ ++pAdapter->hdd_stats.hddArpStats.txDropped;
+ pAdapter->hdd_stats.hddArpStats.reason = HDD_WLANTL_STAPKTPENDING_RETURNED_ERROR_CODE;
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ "%s:ARP Packet Dropped WLANTL_STAPktPending returned error %d",
+ __func__, status);
+ }
++pAdapter->stats.tx_dropped;
++pAdapter->hdd_stats.hddTxRxStats.txXmitDropped;
++pAdapter->hdd_stats.hddTxRxStats.txXmitDroppedAC[qid];
@@ -966,6 +996,14 @@ int __hdd_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
if ( !VOS_IS_STATUS_SUCCESS( status ) )
{
VOS_TRACE( VOS_MODULE_ID_HDD_DATA, VOS_TRACE_LEVEL_WARN,"%s:Insert Tx queue failed. Pkt dropped", __func__);
+
+ if (arp_pkt)
+ {
+ ++pAdapter->hdd_stats.hddArpStats.txDropped;
+ pAdapter->hdd_stats.hddArpStats.reason = HDD_INSERT_TX_QUEUE_FAILED;
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ "%s:Insert Tx queue failed. ARP packet dropped", __func__);
+ }
++pAdapter->hdd_stats.hddTxRxStats.txXmitDropped;
++pAdapter->hdd_stats.hddTxRxStats.txXmitDroppedAC[qid];
++pAdapter->stats.tx_dropped;
@@ -1027,6 +1065,15 @@ int __hdd_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
skb1 = pktNode->skb;
kfree_skb(skb1);
}
+
+ if (arp_pkt)
+ {
+ ++pAdapter->hdd_stats.hddArpStats.txDropped;
+ pAdapter->hdd_stats.hddArpStats.reason = HDD_FAILED_TO_SIGNAL_TL;
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ "%s: ARP packet Dropped : Failed to signal TL for QId=%d",
+ __func__, qid );
+ }
++pAdapter->stats.tx_dropped;
++pAdapter->hdd_stats.hddTxRxStats.txXmitDropped;
++pAdapter->hdd_stats.hddTxRxStats.txXmitDroppedAC[qid];
@@ -1938,6 +1985,7 @@ VOS_STATUS hdd_tx_fetch_packet_cbk( v_VOID_t *vosContext,
tANI_U8 acAdmitted, i;
v_U8_t proto_type = 0;
WLANTL_ACEnumType actualAC;
+ v_BOOL_t arp_pkt;
//Sanity check on inputs
if ( ( NULL == vosContext ) ||
@@ -2075,10 +2123,20 @@ VOS_STATUS hdd_tx_fetch_packet_cbk( v_VOID_t *vosContext,
vos_pkt_return_packet(pVosPacket);
return VOS_STATUS_E_FAILURE;
}
+ arp_pkt = vos_is_arp_pkt(skb, false);
//Attach skb to VOS packet.
status = vos_pkt_set_os_packet( pVosPacket, skb );
if (status != VOS_STATUS_SUCCESS)
{
+
+ if (arp_pkt)
+ {
+ ++pAdapter->hdd_stats.hddArpStats.txDropped;
+ pAdapter->hdd_stats.hddArpStats.reason = HDD_ERROR_ATTACHING_SKB;
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ "%s :Error attaching skb,ARP packet droped", __func__);
+ }
+
VOS_TRACE( VOS_MODULE_ID_HDD_DATA, VOS_TRACE_LEVEL_WARN,"%s: Error attaching skb", __func__);
vos_pkt_return_packet(pVosPacket);
++pAdapter->stats.tx_dropped;
@@ -2090,6 +2148,16 @@ VOS_STATUS hdd_tx_fetch_packet_cbk( v_VOID_t *vosContext,
//Just being paranoid. To be removed later
if(pVosPacket == NULL)
{
+
+ if (arp_pkt)
+ {
+ ++pAdapter->hdd_stats.hddArpStats.txDropped;
+ pAdapter->hdd_stats.hddArpStats.reason = HDD_VOS_PACKET_RETURNED_BY_VOSS_IS_NULL;
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
+ "%s :VOS packet returned by VOSS is NULL,ARP packet droped",
+ __func__);
+ }
+
VOS_TRACE( VOS_MODULE_ID_HDD_DATA, VOS_TRACE_LEVEL_WARN,"%s: VOS packet returned by VOSS is NULL", __func__);
++pAdapter->stats.tx_dropped;
++pAdapter->hdd_stats.hddTxRxStats.txFetchDequeueError;
@@ -2148,6 +2216,12 @@ VOS_STATUS hdd_tx_fetch_packet_cbk( v_VOID_t *vosContext,
if( HDD_ETHERTYPE_ARP_SIZE == packet_size )
pPktMetaInfo->ucIsArp = hdd_IsARP( pVosPacket ) ? 1 : 0;
+ if(pPktMetaInfo->ucIsArp)
+ {
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
+ "%s :STA TX ARP Received in TL ",__func__);
+ }
+
#ifdef FEATURE_WLAN_WAPI
// Override usIsEapol value when its zero for WAPI case
pPktMetaInfo->ucIsWai = hdd_IsWAIPacket( pVosPacket ) ? 1 : 0;
@@ -2543,6 +2617,40 @@ VOS_STATUS hdd_rx_packet_monitor_cbk(v_VOID_t *vosContext,vos_pkt_t *pVosPacket
return status;
}
+bool hdd_is_duplicate_ip_arp(struct sk_buff *skb)
+{
+ struct in_ifaddr **ifap = NULL;
+ struct in_ifaddr *ifa = NULL;
+ struct in_device *in_dev;
+ uint32_t arp_ip,if_ip;
+
+ if (NULL == skb)
+ return false;
+
+ arp_ip = hdd_get_arp_src_ip(skb);
+
+ if(!skb->dev) return false;
+
+ in_dev = __in_dev_get_rtnl(skb->dev);
+
+ if (in_dev) {
+ for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
+ ifap = &ifa->ifa_next) {
+ if (!strcmp(skb->dev->name, ifa->ifa_label))
+ break;
+ }
+ }
+ if (ifa && ifa->ifa_local) {
+
+ if_ip = ntohl(ifa->ifa_local);
+ if (if_ip == arp_ip) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
/**============================================================================
@brief hdd_rx_packet_cbk() - Receive callback registered with TL.
TL will call this to notify the HDD when one or more packets were
@@ -2569,6 +2677,8 @@ VOS_STATUS hdd_rx_packet_cbk( v_VOID_t *vosContext,
vos_pkt_t* pVosPacket;
vos_pkt_t* pNextVosPacket;
v_U8_t proto_type;
+ v_BOOL_t arp_pkt;
+ bool track_arp_resp = false;
//Sanity check on inputs
if ( ( NULL == vosContext ) ||
@@ -2609,6 +2719,14 @@ VOS_STATUS hdd_rx_packet_cbk( v_VOID_t *vosContext,
// both "success" and "empty" are acceptable results
if (!((status == VOS_STATUS_SUCCESS) || (status == VOS_STATUS_E_EMPTY)))
{
+
+ if(hdd_IsARP(pVosPacket))
+ {
+ ++pAdapter->hdd_stats.hddArpStats.rxDropped;
+ pAdapter->hdd_stats.hddArpStats.reason = HDD_FAILURE_WALKING_PACKET_CHAIN;
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ "%s: ARP packet Drop: Failure walking packet chain", __func__);
+ }
++pAdapter->hdd_stats.hddTxRxStats.rxDropped;
VOS_TRACE( VOS_MODULE_ID_HDD_DATA, VOS_TRACE_LEVEL_ERROR,
"%s: Failure walking packet chain", __func__);
@@ -2619,6 +2737,15 @@ VOS_STATUS hdd_rx_packet_cbk( v_VOID_t *vosContext,
status = vos_pkt_get_os_packet( pVosPacket, (v_VOID_t **)&skb, VOS_FALSE );
if(!VOS_IS_STATUS_SUCCESS( status ))
{
+
+ if(hdd_IsARP(pVosPacket))
+ {
+ ++pAdapter->hdd_stats.hddArpStats.rxDropped;
+ pAdapter->hdd_stats.hddArpStats.reason = HDD_FAILURE_EXTRACTING_SKB_FROM_VOS_PKT;
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ "%s: ARP packet Dropped: Failure extracting skb from vos pkt",
+ __func__);
+ }
++pAdapter->hdd_stats.hddTxRxStats.rxDropped;
VOS_TRACE( VOS_MODULE_ID_HDD_DATA, VOS_TRACE_LEVEL_ERROR,
"%s: Failure extracting skb from vos pkt", __func__);
@@ -2680,6 +2807,18 @@ VOS_STATUS hdd_rx_packet_cbk( v_VOID_t *vosContext,
}
}
+ arp_pkt = vos_is_arp_pkt(skb, false);
+
+ if (arp_pkt)
+ {
+ if (pHddCtx->track_arp_ip && vos_check_arp_rsp_src_ip(skb, false)) {
+ ++pAdapter->hdd_stats.hddArpStats.rx_arp_rsp_count;
+ track_arp_resp = true;
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
+ "%s :STA RX ARP received",__func__);
+ }
+ }
+
if (pHddCtx->rx_wow_dump) {
if (!(VOS_PKT_PROTO_TYPE_ARP & proto_type) &&
!(VOS_PKT_PROTO_TYPE_EAPOL & proto_type))
@@ -2703,6 +2842,14 @@ VOS_STATUS hdd_rx_packet_cbk( v_VOID_t *vosContext,
++pAdapter->hdd_stats.hddTxRxStats.rxPackets;
++pAdapter->stats.rx_packets;
pAdapter->stats.rx_bytes += skb->len;
+
+ if (arp_pkt)
+ {
+ pAdapter->dad |= hdd_is_duplicate_ip_arp(skb);
+ if(pAdapter->dad)
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ "%s :Duplicate IP detected",__func__);
+ }
#ifdef WLAN_FEATURE_HOLD_RX_WAKELOCK
vos_wake_lock_timeout_release(&pHddCtx->rx_wake_lock,
HDD_WAKE_LOCK_DURATION,
@@ -2719,11 +2866,30 @@ VOS_STATUS hdd_rx_packet_cbk( v_VOID_t *vosContext,
if (NET_RX_SUCCESS == rxstat)
{
+
+ if (arp_pkt)
+ {
+ if (track_arp_resp) {
+ ++pAdapter->hdd_stats.hddArpStats.rxDelivered;
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
+ "STA RX ARP packet Delivered to net stack");
+ }
+ }
+
++pAdapter->hdd_stats.hddTxRxStats.rxDelivered;
++pAdapter->hdd_stats.hddTxRxStats.pkt_rx_count;
}
else
{
+
+ if (arp_pkt)
+ {
+ ++pAdapter->hdd_stats.hddArpStats.rxRefused;
+ pAdapter->hdd_stats.hddArpStats.reason = HDD_STA_RX_ARP_PACKET_REFUSED_IN_NET_STACK;
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ "%s :STA RX ARP packet Refused in net stack", __func__);
+ }
+
++pAdapter->hdd_stats.hddTxRxStats.rxRefused;
}
// now process the next packet in the chain
diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c
index ef66b168523..5cadb459d21 100644
--- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c
+++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c
@@ -6919,6 +6919,7 @@ static int __iw_get_char_setnone(struct net_device *dev,
hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
hdd_tx_rx_stats_t *pStats = &pAdapter->hdd_stats.hddTxRxStats;
hdd_chip_reset_stats_t *pResetStats = &pHddCtx->hddChipResetStats;
+ hdd_arp_stats_t *parpStats = &pAdapter->hdd_stats.hddArpStats;
snprintf(extra, WE_MAX_STR_LEN,
@@ -6939,6 +6940,11 @@ static int __iw_get_char_setnone(struct net_device *dev,
"\nchains %u, packets %u, dropped %u, delivered %u, refused %u"
"\n\nResetsStats"
"\n TotalLogp %u Cmd53 %u MutexRead %u MIF-Error %u FW-Heartbeat %u Others %u"
+ "\n"
+ "\n\nARP Transmit"
+ "\nTransmit Count %u, dropped %u"
+ "\n\nARP Receive"
+ "\nReceive Count %u, dropped %u, Delivered %u, Refused %u, Drop Reason %u"
"\n",
pStats->txXmitCalled,
pStats->txXmitDropped,
@@ -7012,7 +7018,16 @@ static int __iw_get_char_setnone(struct net_device *dev,
pResetStats->totalMutexReadFailures,
pResetStats->totalMIFErrorFailures,
pResetStats->totalFWHearbeatFailures,
- pResetStats->totalUnknownExceptions
+ pResetStats->totalUnknownExceptions,
+
+ parpStats->tx_arp_req_count,
+ parpStats->txDropped,
+
+ parpStats->rx_arp_rsp_count,
+ parpStats->rxDropped,
+ parpStats->rxDelivered,
+ parpStats->rxRefused,
+ parpStats->reason
);
wrqu->data.length = strlen(extra);
diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wmm.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wmm.c
index e854ad27170..b91f0c8407f 100644
--- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wmm.c
+++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wmm.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@@ -1960,6 +1960,37 @@ void hdd_log_ip_addr(struct sk_buff *skb)
}
/**============================================================================
+ @brief hdd_get_arp_src_ip() - Function to get ARP src IP addr
+ @param skb : [in] pointer to OS packet (sk_buff)
+ @return : IP addr
+ ===========================================================================*/
+uint32_t hdd_get_arp_src_ip(struct sk_buff *skb)
+{
+ struct arphdr *arp;
+ unsigned char *arp_ptr;
+ uint32_t src_ip;
+
+#define ARP_HDR_SIZE ( sizeof(__be16)*3 + sizeof(unsigned char)*2 )
+#define ARP_SENDER_HW_ADDRESS_SZ (6)
+#define ARP_SENDER_IP_ADDRESS_SZ (4)
+
+ arp = (struct arphdr *)skb->data;
+
+ arp_ptr = (unsigned char *)arp + ARP_HDR_SIZE;
+ arp_ptr += ARP_SENDER_HW_ADDRESS_SZ;
+
+ memcpy(&src_ip, arp_ptr, ARP_SENDER_IP_ADDRESS_SZ);
+
+ src_ip=ntohl(src_ip);
+
+ return src_ip;
+
+#undef ARP_HDR_SIZE
+#undef ARP_SENDER_HW_ADDRESS_SZ
+#undef ARP_SENDER_IP_ADDRESS_SZ
+}
+
+/**============================================================================
@brief hdd_wmm_classify_pkt() - Function which will classify an OS packet
into a WMM AC based on either 802.1Q or DSCP
diff --git a/drivers/staging/prima/CORE/MAC/inc/aniGlobal.h b/drivers/staging/prima/CORE/MAC/inc/aniGlobal.h
index 1d50dbfa1b2..ad2df331f60 100644
--- a/drivers/staging/prima/CORE/MAC/inc/aniGlobal.h
+++ b/drivers/staging/prima/CORE/MAC/inc/aniGlobal.h
@@ -260,6 +260,12 @@ typedef struct {
v_TIME_t failed_timestamp[MAX_TIDS];
} tLimStaBAInfo;
+typedef struct {
+ bool tx_aggr;
+ uint8_t sta_id;
+ uint8_t tid;
+} t_test_status_bainfo;
+
typedef struct sAniSirLim
{
////////////////////////////////////// TIMER RELATED START ///////////////////////////////////////////
@@ -914,6 +920,7 @@ tLimMlmOemDataRsp *gpLimMlmOemDataRsp;
tANI_U32 txBdToken;
tANI_U32 EnableTdls2040BSSCoexIE;
tLimStaBAInfo staBaInfo[WLAN_MAX_STA_COUNT];
+ t_test_status_bainfo test_status_bainfo;
} tAniSirLim, *tpAniSirLim;
typedef struct sLimMgmtFrameRegistration
diff --git a/drivers/staging/prima/CORE/MAC/inc/sirApi.h b/drivers/staging/prima/CORE/MAC/inc/sirApi.h
index 3539665ae83..af6bf039314 100644
--- a/drivers/staging/prima/CORE/MAC/inc/sirApi.h
+++ b/drivers/staging/prima/CORE/MAC/inc/sirApi.h
@@ -2929,11 +2929,10 @@ typedef struct sSmeDelBAPeerInd
// Message Type
tANI_U16 mesgType;
- tSirMacAddr bssId;//BSSID
-
// Message Length
tANI_U16 mesgLen;
+ tSirMacAddr bssId;//BSSID
// Station Index
tANI_U16 staIdx;
@@ -3789,11 +3788,57 @@ typedef struct
tANI_U32 reserved2;
}tAniLoggingInitRsp, *tpAniLoggingInitRsp;
+/**
+ * struct rsp_stats - arp packet stats
+ * @status: success or failure
+ * @tx_fw_cnt: tx packets count
+ * @tx_ack_cnt: tx acknowledgement count
+ */
+typedef struct {
+ uint32_t status;
+ uint16_t dad;
+ uint16_t tx_fw_cnt;
+ uint16_t tx_ack_cnt;
+ uint16_t rx_fw_cnt;
+} rsp_stats;
+
+typedef void(*setArpStatsReqCb)(void *data, VOS_STATUS rsp);
+
+/**
+ * struct setArpStatsParams - set/reset arp stats
+ * @flag: enable/disable stats
+ * @pkt_type: type of packet(1 - arp)
+ * @ip_addr: subnet ipv4 address in case of encrypted packets
+ * @rsp_cb_fn: FW response callback api
+ * @data_ctx: parameter for callback api
+ */
+typedef struct {
+ uint8_t flag;
+ uint8_t pkt_type;
+ uint32_t ip_addr;
+ setArpStatsReqCb rsp_cb_fn;
+ void *data_ctx;
+} setArpStatsParams, *psetArpStatsParams;
+
+typedef void(*getArpStatsReqCb)(void *data, rsp_stats *rsp);
+/**
+ * struct getArpStatsParams - get arp stats from firmware
+ * @pkt_type: packet type(1 - ARP)
+ * @get_rsp_cb_fn: FW response callback api
+ * @data_ctx: parameter for callback api
+ */
+typedef struct {
+ uint8_t pkt_type;
+ getArpStatsReqCb get_rsp_cb_fn;
+ void *data_ctx;
+} getArpStatsParams, *pgetArpStatsParams;
+
typedef void(*FWLoggingInitReqCb)(void *fwlogInitCbContext, tAniLoggingInitRsp *pRsp);
typedef void ( *tGetFrameLogCallback) (void *pContext);
typedef void(*RssiMonitorReqCb)(void *rssiMonitorCbContext, VOS_STATUS status);
typedef void(*pktFilterReqCb)(void *data, tANI_U32 status);
+
typedef struct sAniGetFrameLogReq
{
tANI_U16 msgType;
@@ -6063,5 +6108,11 @@ typedef struct {
tANI_U32 value;
} tModifyRoamParamsReqParams, * tpModifyRoamParamsReqParams;
+typedef void(*hdd_conAliveCb)(void *data, bool status);
+
+typedef struct {
+ hdd_conAliveCb rsp_cb_fn;
+ void *data_ctx;
+}getConStatusParams, *pgetConStatusParams;
#endif /* __SIR_API_H */
diff --git a/drivers/staging/prima/CORE/MAC/inc/wniApi.h b/drivers/staging/prima/CORE/MAC/inc/wniApi.h
index ff69d7f4504..bdea77c7c0c 100644
--- a/drivers/staging/prima/CORE/MAC/inc/wniApi.h
+++ b/drivers/staging/prima/CORE/MAC/inc/wniApi.h
@@ -235,6 +235,7 @@ enum eWniMsgTypes
eWNI_SME_PRE_CHANNEL_SWITCH_FULL_POWER,
eWNI_SME_GET_SNR_REQ,
eWNI_SME_LOST_LINK_PARAMS_IND,
+ eWNI_SME_DEL_TEST_BA,
//General Power Save Messages
eWNI_PMC_MSG_TYPES_BEGIN,
eWNI_PMC_PWR_SAVE_CFG,
diff --git a/drivers/staging/prima/CORE/MAC/src/include/sirParams.h b/drivers/staging/prima/CORE/MAC/src/include/sirParams.h
index b91e2fe6378..5dfe0eaf51a 100644
--- a/drivers/staging/prima/CORE/MAC/src/include/sirParams.h
+++ b/drivers/staging/prima/CORE/MAC/src/include/sirParams.h
@@ -144,6 +144,7 @@ typedef enum {
#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD
PER_BASED_ROAMING = 63,
#endif
+ NUD_DEBUG = 68,
//MAX_FEATURE_SUPPORTED = 128
} placeHolderInCapBitmap;
@@ -765,6 +766,12 @@ typedef struct sSirMbMsgP2p
#define SIR_HAL_PER_ROAM_SCAN_TRIGGER_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 289)
#endif
#define SIR_HAL_UPDATE_CFG_INT_PARAM (SIR_HAL_ITC_MSG_TYPES_BEGIN + 290)
+/* ARP Debug stats */
+#define SIR_HAL_SET_ARP_STATS_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 301)
+#define SIR_HAL_GET_ARP_STATS_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 302)
+
+#define SIR_HAL_TRIGGER_ADD_BA_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 303)
+#define SIR_HAL_GET_CON_STATUS (SIR_HAL_ITC_MSG_TYPES_BEGIN + 304)
#define SIR_HAL_MSG_TYPES_END (SIR_HAL_MSG_TYPES_BEGIN + 0x1FF)
// CFG message types
diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessMessageQueue.c b/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessMessageQueue.c
index cb83c73df28..e8b9fced0b3 100644
--- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessMessageQueue.c
+++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessMessageQueue.c
@@ -1625,6 +1625,7 @@ limProcessMessages(tpAniSirGlobal pMac, tpSirMsgQ limMsg)
#endif /* FEATURE_WLAN_ESE && FEATURE_WLAN_ESE_UPLOAD */
case eWNI_SME_MAC_SPOOF_ADDR_IND:
case eWNI_SME_REGISTER_MGMT_FRAME_CB:
+ case eWNI_SME_DEL_TEST_BA:
// These messages are from HDD
limProcessNormalHddMsg(pMac, limMsg, false); //no need to response to hdd
break;
diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessSmeReqMessages.c b/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessSmeReqMessages.c
index 1eafb0ef678..cead21d75b1 100644
--- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessSmeReqMessages.c
+++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessSmeReqMessages.c
@@ -5519,6 +5519,57 @@ static void lim_register_mgmt_frame_ind_cb(tpAniSirGlobal pMac,
limLog(pMac, LOGE, FL("sme_req->callback is null"));
}
+static void lim_delba_con_status(tpAniSirGlobal pMac,
+ void *msg_buf)
+{
+ tpSmeDelBAPeerInd delba_params;
+ tpDphHashNode pSta;
+ tANI_U16 aid;
+ tLimBAState curBaState;
+ tpPESession psessionEntry;
+ tANI_U8 sessionId;
+
+ delba_params = (tpSmeDelBAPeerInd)msg_buf;
+
+ psessionEntry = peFindSessionByBssid(pMac, delba_params->bssId, &sessionId);
+ if (!psessionEntry)
+ {
+ PELOGE(limLog(pMac, LOGE,FL("session does not exist for given BSSId"));)
+ return;
+ }
+
+ pSta = dphLookupHashEntry(pMac, delba_params->bssId, &aid,
+ &psessionEntry->dph.dphHashTable);
+ if(!pSta)
+ {
+ limLog(pMac, LOGE,
+ FL("STA context not found - ignoring BA Delete IND from HAL"));
+ return;
+ }
+
+ LIM_GET_STA_BA_STATE(pSta, delba_params->baTID, &curBaState);
+ if( eLIM_BA_STATE_IDLE != curBaState )
+ {
+ limLog(pMac, LOGE,
+ FL("Received unexpected BA Delete IND when STA BA state is %d"),
+ curBaState);
+ return;
+ }
+
+ if(eSIR_SUCCESS != limPostMlmDelBAReq(pMac, pSta,
+ delba_params->baDirection,
+ delba_params->baTID,
+ eSIR_MAC_PEER_REJECT_MECHANISIM_REASON,
+ psessionEntry)) {
+ limLog(pMac, LOGE, FL("Post DEL BA request failed"));
+ }
+ else
+ {
+ limLog(pMac, LOG1, FL(" Delete BA session StaId %d on tid %d"),
+ delba_params->staIdx, delba_params->baTID);
+ }
+}
+
/**
* limProcessSmeReqMessages()
*
@@ -5865,6 +5916,9 @@ limProcessSmeReqMessages(tpAniSirGlobal pMac, tpSirMsgQ pMsg)
case eWNI_SME_REGISTER_MGMT_FRAME_CB:
lim_register_mgmt_frame_ind_cb(pMac, pMsgBuf);
break;
+ case eWNI_SME_DEL_TEST_BA:
+ lim_delba_con_status(pMac, pMsgBuf);
+ break;
default:
vos_mem_free((v_VOID_t*)pMsg->bodyptr);
pMsg->bodyptr = NULL;
diff --git a/drivers/staging/prima/CORE/SME/inc/sme_Api.h b/drivers/staging/prima/CORE/SME/inc/sme_Api.h
index 41a1640ae52..cf65a45270b 100644
--- a/drivers/staging/prima/CORE/SME/inc/sme_Api.h
+++ b/drivers/staging/prima/CORE/SME/inc/sme_Api.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@@ -3961,4 +3961,15 @@ eHalStatus sme_remove_bssid_from_scan_list(tHalHandle hal,
void sme_set_mgmt_frm_via_wq5(tHalHandle hHal,
tANI_BOOLEAN sendMgmtPktViaWQ5);
eHalStatus sme_update_cfg_int_param(tHalHandle hHal, tANI_U32 cfg_id);
+
+/* ARP DEBUG STATS */
+eHalStatus sme_set_nud_debug_stats(tHalHandle hHal,
+ psetArpStatsParams pSetStatsParam);
+eHalStatus sme_get_nud_debug_stats(tHalHandle hHal,
+ pgetArpStatsParams pGetStatsParam);
+eHalStatus sme_test_con_alive(tHalHandle hHal);
+eHalStatus sme_get_con_alive(tHalHandle hHal,
+ pgetConStatusParams conStatusParams);
+eHalStatus sme_test_con_delba(tHalHandle hHal, uint8_t sta_id,
+ uint8_t session_id);
#endif //#if !defined( __SME_API_H )
diff --git a/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c b/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c
index 947489cd87e..23ab858c355 100644
--- a/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c
+++ b/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c
@@ -2281,6 +2281,18 @@ static tANI_S32 csrFindSelfCongestionScore(tpAniSirGlobal pMac,
if (pSession == NULL)
return -1;
+ if (bssInfo->rssi < pMac->roam.configParam.PERMinRssiThresholdForRoam) {
+ smsLog(pMac, LOG1,
+ FL("Current AP has low rssi=%d than %d"), bssInfo->rssi,
+ pMac->roam.configParam.PERMinRssiThresholdForRoam);
+ /*
+ * Make Current candidate score as zero which will cause roaming
+ * in low RSSI scenarios
+ */
+ pMac->currentBssScore = 0;
+ return 0;
+ }
+
for (i = 0; i <= pMac->PERroamCandidatesCnt; i++)
if (pMac->candidateChannelInfo[i].channelNumber == bssInfo->channelId)
break;
diff --git a/drivers/staging/prima/CORE/SME/src/sme_common/sme_Api.c b/drivers/staging/prima/CORE/SME/src/sme_common/sme_Api.c
index 158b36adb58..dbcbccb66d4 100644
--- a/drivers/staging/prima/CORE/SME/src/sme_common/sme_Api.c
+++ b/drivers/staging/prima/CORE/SME/src/sme_common/sme_Api.c
@@ -14419,3 +14419,167 @@ void sme_set_mgmt_frm_via_wq5(tHalHandle hHal, tANI_BOOLEAN sendMgmtPktViaWQ5)
}
return;
}
+
+/* ARP DEBUG STATS */
+
+/**
+ * sme_set_nud_debug_stats() - sme api to set nud debug stats
+ * @hHal: handle to hal
+ * @pSetStatsParam: pointer to set stats param
+ */
+eHalStatus sme_set_nud_debug_stats(tHalHandle hHal,
+ setArpStatsParams *pSetStatsParam)
+{
+ setArpStatsParams *arp_set_param;
+ vos_msg_t msg;
+
+ arp_set_param = vos_mem_malloc(sizeof(*arp_set_param));
+ if (arp_set_param == NULL) {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ FL("Memory allocation failure"));
+ return VOS_STATUS_E_NOMEM;
+ }
+
+ vos_mem_copy(arp_set_param, pSetStatsParam, sizeof(*arp_set_param));
+
+ msg.type = WDA_SET_ARP_STATS_REQ;
+ msg.reserved = 0;
+ msg.bodyptr = arp_set_param;
+
+ if (VOS_STATUS_SUCCESS != vos_mq_post_message(VOS_MODULE_ID_WDA, &msg)) {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ FL("Not able to post message to WDA"));
+ vos_mem_free(arp_set_param);
+ return VOS_STATUS_E_FAILURE;
+ }
+
+ return VOS_STATUS_SUCCESS;
+}
+
+/**
+ * sme_get_nud_debug_stats() - sme api to get nud debug stats
+ * @hHal: handle to hal
+ * @pGetStatsParam: pointer to set stats param
+ */
+eHalStatus sme_get_nud_debug_stats(tHalHandle hHal,
+ getArpStatsParams *pGetStatsParam)
+{
+ getArpStatsParams *arpGetParams;
+ vos_msg_t msg;
+
+ arpGetParams = vos_mem_malloc(sizeof(*arpGetParams));
+ if (arpGetParams == NULL) {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ FL("Memory allocation failure"));
+ return VOS_STATUS_E_NOMEM;
+ }
+
+ vos_mem_copy(arpGetParams, pGetStatsParam, sizeof(*arpGetParams));
+
+ msg.type = WDA_GET_ARP_STATS_REQ;
+ msg.reserved = 0;
+ msg.bodyptr = arpGetParams;
+
+ if (VOS_STATUS_SUCCESS != vos_mq_post_message(VOS_MODULE_ID_WDA, &msg)) {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ FL("Not able to post message to WDA"));
+ vos_mem_free(arpGetParams);
+ return VOS_STATUS_E_FAILURE;
+ }
+
+ return VOS_STATUS_SUCCESS;
+}
+
+eHalStatus sme_test_con_alive(tHalHandle hHal)
+{
+ vos_msg_t wdaMsg = {0};
+
+ wdaMsg.type = WDA_TRIGGER_ADD_BA_REQ;
+ wdaMsg.bodyptr = NULL;
+ wdaMsg.reserved = 0;
+
+ if (VOS_STATUS_SUCCESS != vos_mq_post_message(VOS_MQ_ID_WDA, &wdaMsg))
+ return VOS_STATUS_E_FAILURE;
+
+ return VOS_STATUS_SUCCESS;
+}
+
+
+eHalStatus sme_get_con_alive(tHalHandle hHal,
+ pgetConStatusParams conStatusParams)
+{
+ vos_msg_t wdaMsg = {0};
+ pgetConStatusParams statusParams;
+ VOS_STATUS vosStatus;
+
+ statusParams = vos_mem_malloc(sizeof(getConStatusParams));
+ if (NULL == statusParams) {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ FL("Memory allocation failure"));
+ return VOS_STATUS_E_NOMEM;
+ }
+
+ vos_mem_copy(statusParams, conStatusParams, sizeof(getConStatusParams));
+ wdaMsg.type = WDA_GET_CON_STATUS;
+ wdaMsg.bodyptr = statusParams;
+ wdaMsg.reserved = 0;
+
+ vosStatus = vos_mq_post_message(VOS_MQ_ID_WDA, &wdaMsg);
+ if (!VOS_IS_STATUS_SUCCESS(vosStatus)) {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ FL(" Not able to post message"));
+ vos_mem_free(statusParams);
+ return VOS_STATUS_E_FAILURE;
+ }
+
+ return VOS_STATUS_SUCCESS;
+}
+
+eHalStatus sme_test_con_delba(tHalHandle hHal, uint8_t sta_id,
+ uint8_t session_id)
+{
+ tpSmeDelBAPeerInd msg;
+ tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, session_id);
+ eHalStatus status = eHAL_STATUS_FAILURE;
+
+ if (!CSR_IS_SESSION_VALID(pMac, session_id))
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ FL("Session is invalid"));
+ return status;
+ }
+
+ if (!pMac->lim.test_status_bainfo.tx_aggr)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ FL("BA session not established"));
+ return status;
+ }
+
+ if (eHAL_STATUS_SUCCESS == sme_AcquireGlobalLock(&pMac->sme))
+ {
+ msg = vos_mem_malloc(sizeof(tSmeDelBAPeerInd));
+ if (NULL == msg)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ FL("Memory allocation failure"));
+ return VOS_STATUS_E_NOMEM;
+ }
+
+ msg->staIdx = sta_id;
+ msg->baTID = pMac->lim.test_status_bainfo.tid;
+ vos_mem_copy(msg->bssId, pSession->connectedProfile.bssid,
+ sizeof(tSirMacAddr));
+ msg->baDirection = eBA_INITIATOR;
+
+ msg->mesgType = eWNI_SME_DEL_TEST_BA;
+ msg->mesgLen = sizeof(tSmeDelBAPeerInd);
+
+ status = palSendMBMessage(pMac->hHdd, msg);
+
+ sme_ReleaseGlobalLock(&pMac->sme);
+ }
+
+ return status;
+}
diff --git a/drivers/staging/prima/CORE/SYS/legacy/src/utils/src/macTrace.c b/drivers/staging/prima/CORE/SYS/legacy/src/utils/src/macTrace.c
index 12a8a6b5a40..0da70dc30c0 100644
--- a/drivers/staging/prima/CORE/SYS/legacy/src/utils/src/macTrace.c
+++ b/drivers/staging/prima/CORE/SYS/legacy/src/utils/src/macTrace.c
@@ -906,6 +906,10 @@ tANI_U8* macTraceGetWdaMsgString( tANI_U16 wdaMsg )
CASE_RETURN_STRING(WDA_MON_STOP_REQ);
CASE_RETURN_STRING(WDA_SPOOF_MAC_ADDR_REQ);
CASE_RETURN_STRING(WDA_LOST_LINK_PARAMS_IND);
+ CASE_RETURN_STRING(WDA_SET_ARP_STATS_REQ);
+ CASE_RETURN_STRING(WDA_GET_ARP_STATS_REQ);
+ CASE_RETURN_STRING(WDA_TRIGGER_ADD_BA_REQ);
+ CASE_RETURN_STRING(WDA_GET_CON_STATUS);
default:
return((tANI_U8*) "UNKNOWN" );
break;
diff --git a/drivers/staging/prima/CORE/TL/inc/wlan_qct_tl.h b/drivers/staging/prima/CORE/TL/inc/wlan_qct_tl.h
index 9b80e046023..35d9f7d976b 100644
--- a/drivers/staging/prima/CORE/TL/inc/wlan_qct_tl.h
+++ b/drivers/staging/prima/CORE/TL/inc/wlan_qct_tl.h
@@ -3376,4 +3376,13 @@ void WLANTL_ResetRxSSN(v_PVOID_t pvosGCtx, uint8_t ucSTAId);
* Return: none
*/
void WLANTL_SetDataPktFilter(v_PVOID_t pvosGCtx, uint8_t ucSTAId, bool flag);
+
+/**
+ * WLANTL_SetARPFWDatapath() - keep or remove FW in data path for ARP
+ * @pvosGCtx: global vos context
+ * @flag: value to keep or remove FW from data path
+ *
+ * Return: void
+ */
+void WLANTL_SetARPFWDatapath(void * pvosGCtx, bool flag);
#endif /* #ifndef WLAN_QCT_WLANTL_H */
diff --git a/drivers/staging/prima/CORE/TL/src/wlan_qct_tl.c b/drivers/staging/prima/CORE/TL/src/wlan_qct_tl.c
index ae95be50dd7..09754b8a967 100644
--- a/drivers/staging/prima/CORE/TL/src/wlan_qct_tl.c
+++ b/drivers/staging/prima/CORE/TL/src/wlan_qct_tl.c
@@ -2752,8 +2752,8 @@ WLANTL_TxBAPFrm
ucWDSEnabled, extraHeadSpace, pMetaInfo->ucType,
&pTLCb->atlSTAClients[ucStaId]->wSTADesc.vSelfMACAddress,
pMetaInfo->ucTID, 0 /* No ACK */, pMetaInfo->usTimeStamp,
- pMetaInfo->ucIsEapol || pMetaInfo->ucIsWai, pMetaInfo->ucUP,
- pMetaInfo->ucTxBdToken);
+ pMetaInfo->ucIsEapol || pMetaInfo->ucIsWai, pMetaInfo->ucIsArp,
+ pMetaInfo->ucUP, pMetaInfo->ucTxBdToken);
if ( VOS_STATUS_SUCCESS != vosStatus )
{
@@ -3694,7 +3694,7 @@ WLANTL_TxMgmtFrm
vosStatus = WDA_DS_BuildTxPacketInfo( pvosGCtx, vosFrmBuf , &vDestMacAddr,
1 /* always 802.11 frames*/, &usPktLen, uQosHdr /*qos not enabled !!!*/,
0 /* WDS off */, 0, wFrmType, pvAddr2MacAddr, ucTid,
- ucAckResponse, usTimeStamp, 0, 0, ucTxBdToken);
+ ucAckResponse, usTimeStamp, 0, 0, 0, ucTxBdToken);
if ( !VOS_IS_STATUS_SUCCESS(vosStatus) )
@@ -7887,8 +7887,8 @@ WLANTL_STATxConn
extraHeadSpace,
ucTypeSubtype, &pClientSTA->wSTADesc.vSelfMACAddress,
ucTid, txFlag,
- tlMetaInfo.usTimeStamp, tlMetaInfo.ucIsEapol || tlMetaInfo.ucIsWai, tlMetaInfo.ucUP,
- tlMetaInfo.ucTxBdToken);
+ tlMetaInfo.usTimeStamp, tlMetaInfo.ucIsEapol || tlMetaInfo.ucIsWai,
+ tlMetaInfo.ucIsArp, tlMetaInfo.ucUP, tlMetaInfo.ucTxBdToken);
if ( VOS_STATUS_SUCCESS != vosStatus )
{
@@ -8307,6 +8307,18 @@ WLANTL_STATxAuth
#endif /* FEATURE_WLAN_TDLS */
if( tlMetaInfo.ucIsArp )
{
+ if (pTLCb->track_arp)
+ {
+ if (vos_check_arp_req_target_ip(vosDataBuff->pSkb, true))
+ {
+ ucTxFlag |= HAL_USE_FW_IN_TX_PATH;
+ ucTxFlag |= HAL_TXCOMP_REQUESTED_MASK;
+ tlMetaInfo.ucTxBdToken = ++ pTLCb->txbd_token;
+ TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,
+ "%s: ARP packet FW in data path", __func__));
+ }
+ }
+
if (pStaClient->arpOnWQ5)
{
ucTxFlag |= HAL_USE_FW_IN_TX_PATH;
@@ -8331,7 +8343,7 @@ WLANTL_STATxAuth
extraHeadSpace,
ucTypeSubtype, &pStaClient->wSTADesc.vSelfMACAddress,
ucTid, ucTxFlag, tlMetaInfo.usTimeStamp,
- tlMetaInfo.ucIsEapol, tlMetaInfo.ucUP,
+ tlMetaInfo.ucIsEapol, tlMetaInfo.ucIsArp, tlMetaInfo.ucUP,
tlMetaInfo.ucTxBdToken);
if(!VOS_IS_STATUS_SUCCESS(vosStatus))
@@ -13816,6 +13828,29 @@ void WLANTL_ResetRxSSN(v_PVOID_t pvosGCtx, uint8_t ucSTAId)
}
}
+/**
+ * WLANTL_SetARPFWDatapath() - keep or remove FW in data path for ARP
+ *
+ * @flag: value to keep or remove FW from data path
+ *
+ * Return: void
+ */
+void WLANTL_SetARPFWDatapath(void * pvosGCtx, bool flag)
+{
+
+ WLANTL_CbType* pTLCb = NULL;
+
+ pTLCb = VOS_GET_TL_CB(pvosGCtx);
+ if (NULL == pTLCb) {
+ TLLOGE(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
+ "%s: Invalid TL pointer from pvosGCtx", __func__));
+ return;
+ }
+
+ pTLCb->track_arp = flag;
+
+}
+
#ifdef WLAN_FEATURE_RMC
VOS_STATUS WLANTL_RmcInit
(
diff --git a/drivers/staging/prima/CORE/TL/src/wlan_qct_tl_ba.c b/drivers/staging/prima/CORE/TL/src/wlan_qct_tl_ba.c
index f9405850412..ccfcfb0c699 100644
--- a/drivers/staging/prima/CORE/TL/src/wlan_qct_tl_ba.c
+++ b/drivers/staging/prima/CORE/TL/src/wlan_qct_tl_ba.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@@ -1165,6 +1165,12 @@ VOS_STATUS WLANTL_MSDUReorder
TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,
"(QCUR_FWDBUF) dropping old frame, SN=%d LastSN=%d",
CSN, currentReorderInfo->LastSN));
+ if (vos_is_arp_pkt((*vosDataBuff)->pSkb, true))
+ {
+ if (vos_check_arp_rsp_src_ip((*vosDataBuff)->pSkb, true))
+ vos_update_arp_rx_drop_reorder();
+ }
+
status = vos_pkt_return_packet(*vosDataBuff);
if (!VOS_IS_STATUS_SUCCESS(status))
{
diff --git a/drivers/staging/prima/CORE/TL/src/wlan_qct_tli.h b/drivers/staging/prima/CORE/TL/src/wlan_qct_tli.h
index 4d23eb22781..fdb5898b8fb 100644
--- a/drivers/staging/prima/CORE/TL/src/wlan_qct_tli.h
+++ b/drivers/staging/prima/CORE/TL/src/wlan_qct_tli.h
@@ -967,6 +967,8 @@ typedef struct
WLANTL_RoamMonitorType gDsRxRoamStats;
#endif
+ uint8_t track_arp;
+ uint32_t txbd_token;
}WLANTL_CbType;
diff --git a/drivers/staging/prima/CORE/VOSS/inc/vos_api.h b/drivers/staging/prima/CORE/VOSS/inc/vos_api.h
index b1b846cd3f9..898a039c4b7 100644
--- a/drivers/staging/prima/CORE/VOSS/inc/vos_api.h
+++ b/drivers/staging/prima/CORE/VOSS/inc/vos_api.h
@@ -526,4 +526,11 @@ v_BOOL_t vos_is_probe_rsp_offload_enabled(void);
void vos_smd_dump_stats(void);
void vos_log_wdi_event(uint16 msg, vos_wdi_trace_event_type event);
void vos_dump_wdi_events(void);
+
+bool vos_check_arp_target_ip(void *pSkb, bool conversion);
+bool vos_check_arp_req_target_ip(void *pSkb, bool conversion);
+bool vos_check_arp_src_ip(void *pSkb, bool conversion);
+bool vos_check_arp_rsp_src_ip(void *pSkb, bool conversion);
+void vos_update_arp_fw_tx_delivered(void);
+void vos_update_arp_rx_drop_reorder(void);
#endif // if !defined __VOS_NVITEM_H
diff --git a/drivers/staging/prima/CORE/VOSS/inc/vos_packet.h b/drivers/staging/prima/CORE/VOSS/inc/vos_packet.h
index 3aa0a33b55e..06e8e2c9ef2 100644
--- a/drivers/staging/prima/CORE/VOSS/inc/vos_packet.h
+++ b/drivers/staging/prima/CORE/VOSS/inc/vos_packet.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@@ -53,6 +53,16 @@
#define VOS_PKT_PROTO_TYPE_EAPOL 0x02
#define VOS_PKT_PROTO_TYPE_DHCP 0x04
#define VOS_PKT_PROTO_TYPE_ARP 0x08
+
+/* ARP packet offset values */
+#define VOS_PKT_ARP_OPCODE_OFFSET 20
+#define VOS_PKT_ARPOP_REQUEST 1
+#define VOS_PKT_ARPOP_REPLY 2
+#define VOS_ARP_TARGET_IP_OFFSET 38
+#define VOS_ARP_SRC_IP_OFFSET 28
+
+#define VOS_80211_8023_HEADER_OFFSET 20
+
/*--------------------------------------------------------------------------
Type declarations
------------------------------------------------------------------------*/
@@ -1170,4 +1180,16 @@ v_PVOID_t vos_get_pkt_end(vos_pkt_t *pPacket);
*/
v_VOID_t vos_recover_tail(vos_pkt_t *pPacket);
+/**
+ @breaf vos_is_arp_pkt() - Check the packet is ARP or not.
+
+ @param
+ pskb - pointer to skb
+ is_translated - header translation check
+ @return
+ TRUE - if packet is ARP
+ FALSE -if packet is not ARP
+*/
+bool vos_is_arp_pkt(void *pskb, bool is_translated);
+
#endif // !defined( __VOS_PKT_H )
diff --git a/drivers/staging/prima/CORE/VOSS/src/vos_api.c b/drivers/staging/prima/CORE/VOSS/src/vos_api.c
index f218b8e5d3a..881a2b59bd6 100644
--- a/drivers/staging/prima/CORE/VOSS/src/vos_api.c
+++ b/drivers/staging/prima/CORE/VOSS/src/vos_api.c
@@ -3664,3 +3664,268 @@ void vos_dump_wdi_events(void)
gvos_wdi_msg_trace[i].message);
}
}
+/**
+ * vos_check_arp_target_ip() - check if the Target IP is gateway IP
+ * @pPacket: pointer to vos packet
+ * @conversion: 802.3 to 802.11 frame conversion
+ *
+ * Return: true if the IP is of gateway or false otherwise
+ */
+bool vos_check_arp_target_ip(void *pSkb, bool conversion)
+{
+ v_CONTEXT_t pVosContext = vos_get_global_context(VOS_MODULE_ID_SYS, NULL);
+ hdd_context_t *pHddCtx = NULL;
+ struct sk_buff *skb;
+ uint8_t offset;
+
+ if(!pVosContext)
+ {
+ hddLog(VOS_TRACE_LEVEL_FATAL,"%s: Global VOS context is Null", __func__);
+ return false;
+ }
+
+ pHddCtx = (hdd_context_t *)vos_get_context(VOS_MODULE_ID_HDD, pVosContext );
+ if(!pHddCtx) {
+ VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL,
+ "%s: HDD context is Null", __func__);
+ return false;
+ }
+
+ if (unlikely(NULL == pSkb))
+ {
+ VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL,
+ "%s: NULL pointer", __func__);
+ return false;
+ }
+
+ skb = (struct sk_buff *)pSkb;
+
+ if (conversion)
+ offset = VOS_ARP_TARGET_IP_OFFSET + VOS_80211_8023_HEADER_OFFSET;
+ else
+ offset = VOS_ARP_TARGET_IP_OFFSET;
+
+ if (pHddCtx->track_arp_ip ==
+ (v_U32_t)(*(v_U32_t *)(skb->data + offset)))
+ return true;
+
+ return false;
+}
+
+/**
+ * vos_check_arp_req_target_ip() - check if the ARP is request and
+ target IP is gateway
+ * @pPacket: pointer to vos packet
+ * @conversion: 802.3 to 802.11 frame conversion
+ *
+ * Return: true if the IP is of gateway or false otherwise
+ */
+bool vos_check_arp_req_target_ip(void *pSkb, bool conversion)
+{
+ v_CONTEXT_t pVosContext = vos_get_global_context(VOS_MODULE_ID_SYS, NULL);
+ struct sk_buff *skb;
+ uint8_t offset;
+
+ if(!pVosContext)
+ {
+ hddLog(VOS_TRACE_LEVEL_FATAL,"%s: Global VOS context is Null", __func__);
+ return false;
+ }
+
+ if (unlikely(NULL == pSkb))
+ {
+ VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL,
+ "%s: NULL pointer", __func__);
+ return false;
+ }
+
+ skb = (struct sk_buff *)pSkb;
+
+ if (conversion)
+ offset = VOS_PKT_ARP_OPCODE_OFFSET + VOS_80211_8023_HEADER_OFFSET;
+ else
+ offset = VOS_PKT_ARP_OPCODE_OFFSET;
+
+ if (htons(VOS_PKT_ARPOP_REQUEST) ==
+ (uint16_t)(*(uint16_t *)(skb->data + offset)))
+ {
+ if (vos_check_arp_target_ip(skb, conversion))
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * vos_check_arp_src_ip() - check if the ARP response src IP is gateway IP
+ * @pPacket: pointer to vos packet
+ * @conversion: 802.3 to 802.11 frame conversion
+ *
+ * Return: true if the IP is of gateway or false otherwise
+ */
+bool vos_check_arp_src_ip(void *pSkb, bool conversion)
+{
+ v_CONTEXT_t pVosContext = vos_get_global_context(VOS_MODULE_ID_SYS, NULL);
+ hdd_context_t *pHddCtx = NULL;
+ struct sk_buff *skb;
+ uint8_t offset;
+
+ if(!pVosContext)
+ {
+ hddLog(VOS_TRACE_LEVEL_FATAL,"%s: Global VOS context is Null", __func__);
+ return false;
+ }
+
+ pHddCtx = (hdd_context_t *)vos_get_context(VOS_MODULE_ID_HDD, pVosContext );
+ if(!pHddCtx) {
+ VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL,
+ "%s: HDD context is Null", __func__);
+ return false;
+ }
+
+ if (unlikely(NULL == pSkb))
+ {
+ VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL,
+ "%s: NULL pointer", __func__);
+ return false;
+ }
+
+ skb = (struct sk_buff *)pSkb;
+
+ if (conversion)
+ offset = VOS_ARP_SRC_IP_OFFSET + VOS_80211_8023_HEADER_OFFSET;
+ else
+ offset = VOS_ARP_SRC_IP_OFFSET;
+
+ if (pHddCtx->track_arp_ip ==
+ (v_U32_t)(*(v_U32_t *)(skb->data + offset)))
+ return true;
+
+ return false;
+}
+
+/**
+ * vos_check_arp_rsp_src_ip() - check if the ARP is request and
+ target IP is gateway
+ * @pPacket: pointer to vos packet
+ * @conversion: 802.3 to 802.11 frame conversion
+ *
+ * Return: true if the IP is of gateway or false otherwise
+ */
+bool vos_check_arp_rsp_src_ip(void *pSkb, bool conversion)
+{
+ v_CONTEXT_t pVosContext = vos_get_global_context(VOS_MODULE_ID_SYS, NULL);
+ struct sk_buff *skb;
+ uint8_t offset;
+
+ if(!pVosContext)
+ {
+ hddLog(VOS_TRACE_LEVEL_FATAL,"%s: Global VOS context is Null", __func__);
+ return false;
+ }
+
+ if (unlikely(NULL == pSkb))
+ {
+ VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL,
+ "%s: NULL pointer", __func__);
+ return false;
+ }
+
+ skb = (struct sk_buff *)pSkb;
+
+ if (conversion)
+ offset = VOS_PKT_ARP_OPCODE_OFFSET + VOS_80211_8023_HEADER_OFFSET;
+ else
+ offset = VOS_PKT_ARP_OPCODE_OFFSET;
+
+ if (htons(VOS_PKT_ARPOP_REPLY) ==
+ (uint16_t)(*(uint16_t *)(skb->data + offset)))
+ {
+ if (vos_check_arp_src_ip(skb, conversion))
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * vos_update_arp_fw_tx_delivered() - update the ARP stats host to FW deliver
+ * count
+ *
+ * Return: None
+ */
+void vos_update_arp_fw_tx_delivered(void)
+{
+ v_CONTEXT_t pVosContext = vos_get_global_context(VOS_MODULE_ID_SYS, NULL);
+ hdd_context_t *pHddCtx = NULL;
+ hdd_adapter_t * pAdapter;
+ hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
+ uint8_t status;
+
+ if(!pVosContext) {
+ hddLog(VOS_TRACE_LEVEL_FATAL,"%s: Global VOS context is Null", __func__);
+ return;
+ }
+
+ pHddCtx = (hdd_context_t *)vos_get_context(VOS_MODULE_ID_HDD, pVosContext );
+ if(!pHddCtx) {
+ VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL,
+ "%s: HDD context is Null", __func__);
+ return;
+ }
+
+ status = hdd_get_front_adapter(pHddCtx, &pAdapterNode);
+
+ while (NULL != pAdapterNode && 0 == status)
+ {
+ pAdapter = pAdapterNode->pAdapter;
+ if (pAdapter->device_mode == WLAN_HDD_INFRA_STATION)
+ break;
+
+ status = hdd_get_next_adapter (pHddCtx, pAdapterNode, &pNext);
+ pAdapterNode = pNext;
+ }
+
+ pAdapter->hdd_stats.hddArpStats.tx_host_fw_sent++;
+}
+
+/**
+ * vos_update_arp_rx_drop_reorder() - update the RX ARP stats drop due
+ * reorder logic at host
+ *
+ * Return: None
+ */
+void vos_update_arp_rx_drop_reorder(void)
+{
+ v_CONTEXT_t pVosContext = vos_get_global_context(VOS_MODULE_ID_SYS, NULL);
+ hdd_context_t *pHddCtx = NULL;
+ hdd_adapter_t * pAdapter;
+ hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
+ uint8_t status;
+
+ if(!pVosContext) {
+ hddLog(VOS_TRACE_LEVEL_FATAL,"%s: Global VOS context is Null", __func__);
+ return;
+ }
+
+ pHddCtx = (hdd_context_t *)vos_get_context(VOS_MODULE_ID_HDD, pVosContext );
+ if(!pHddCtx) {
+ VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL,
+ "%s: HDD context is Null", __func__);
+ return;
+ }
+
+ status = hdd_get_front_adapter(pHddCtx, &pAdapterNode);
+
+ while (NULL != pAdapterNode && 0 == status)
+ {
+ pAdapter = pAdapterNode->pAdapter;
+ if (pAdapter->device_mode == WLAN_HDD_INFRA_STATION)
+ break;
+
+ status = hdd_get_next_adapter (pHddCtx, pAdapterNode, &pNext);
+ pAdapterNode = pNext;
+ }
+
+ pAdapter->hdd_stats.hddArpStats.rx_host_drop_reorder++;
+}
diff --git a/drivers/staging/prima/CORE/VOSS/src/vos_packet.c b/drivers/staging/prima/CORE/VOSS/src/vos_packet.c
index 43daf9f7d37..733217687af 100644
--- a/drivers/staging/prima/CORE/VOSS/src/vos_packet.c
+++ b/drivers/staging/prima/CORE/VOSS/src/vos_packet.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@@ -3100,6 +3100,35 @@ v_U8_t vos_pkt_get_proto_type
return pkt_proto_type;
}
+bool vos_is_arp_pkt(void *pskb, bool is_translated)
+{
+ v_U16_t ether_type;
+ struct sk_buff *skb = NULL;
+#define HEADER_OFFSET_802_11 20
+
+ if (NULL == pskb)
+ {
+ return FALSE;
+ }
+
+ skb = (struct sk_buff *)pskb;
+
+ if (is_translated)
+ ether_type = (v_U16_t)(*(v_U16_t *)(skb->data + VOS_PKT_PROT_ETH_TYPE_OFFSET + HEADER_OFFSET_802_11));
+ else
+ ether_type = (v_U16_t)(*(v_U16_t *)(skb->data + VOS_PKT_PROT_ETH_TYPE_OFFSET));
+
+ if (VOS_PKT_PROT_ARP_ETH_TYPE == VOS_SWAP_U16(ether_type))
+ {
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+#undef HEADER_OFFSET_802_11
+}
+
v_PVOID_t vos_get_pkt_head(vos_pkt_t *pPacket)
{
struct sk_buff *skb;
diff --git a/drivers/staging/prima/CORE/WDA/inc/wlan_qct_wda.h b/drivers/staging/prima/CORE/WDA/inc/wlan_qct_wda.h
index d058e45ac0d..fdc768d8ca4 100644
--- a/drivers/staging/prima/CORE/WDA/inc/wlan_qct_wda.h
+++ b/drivers/staging/prima/CORE/WDA/inc/wlan_qct_wda.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@@ -525,6 +525,10 @@ typedef struct
uint8_t mgmt_pktfree_fail;
vos_lock_t mgmt_pkt_lock;
+ /* debug connection status */
+ bool tx_aggr;
+ uint8_t sta_id;
+ uint8_t tid;
} tWDA_CbContext ;
typedef struct
@@ -1291,6 +1295,12 @@ tSirRetStatus uMacPostCtrlMsg(void* pSirGlobal, tSirMbMsg* pMb);
#define WDA_START_RSSI_MONITOR_REQ SIR_HAL_RSSI_MON_START_REQ
#define WDA_STOP_RSSI_MONITOR_REQ SIR_HAL_RSSI_MON_STOP_REQ
+/* ARP Debug */
+#define WDA_SET_ARP_STATS_REQ SIR_HAL_SET_ARP_STATS_REQ
+#define WDA_GET_ARP_STATS_REQ SIR_HAL_GET_ARP_STATS_REQ
+#define WDA_TRIGGER_ADD_BA_REQ SIR_HAL_TRIGGER_ADD_BA_REQ
+#define WDA_GET_CON_STATUS SIR_HAL_GET_CON_STATUS
+
tSirRetStatus wdaPostCtrlMsg(tpAniSirGlobal pMac, tSirMsgQ *pMsg);
eHalStatus WDA_SetRegDomain(void * clientCtxt, v_REGDOMAIN_t regId,
@@ -1598,6 +1608,7 @@ WDA_DS_FinishULA
txFlag
timeStamp
ucIsEapol
+ ucIsArp
ucUP
OUT
@@ -1627,6 +1638,7 @@ WDA_DS_BuildTxPacketInfo
v_U32_t txFlag,
v_U32_t timeStamp,
v_U8_t ucIsEapol,
+ v_U8_t ucIsArp,
v_U8_t ucUP,
v_U32_t ucTxBdToken
);
diff --git a/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c b/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c
index d6df4091f01..f88a83b8398 100644
--- a/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c
+++ b/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c
@@ -165,7 +165,12 @@ void WDA_lowLevelIndCallback(WDI_LowLevelIndType *wdiLowLevelInd,
static VOS_STATUS wdaCreateTimers(tWDA_CbContext *pWDA) ;
static VOS_STATUS wdaDestroyTimers(tWDA_CbContext *pWDA);
bool WDA_AllowAddBA(tpAniSirGlobal pMAc, tANI_U8 staId, tANI_U8 tid);
-void WDA_BaCheckActivity(tWDA_CbContext *pWDA) ;
+void WDA_BaCheckActivity(tWDA_CbContext *pWDA, bool test_con);
+
+/* check connection status */
+void WDA_GetConnectionStatus(tWDA_CbContext *pWDA,
+ getConStatusParams *conStatusParams);
+
void WDA_TimerTrafficStatsInd(tWDA_CbContext *pWDA);
void WDA_HALDumpCmdCallback(WDI_HALDumpCmdRspParamsType *wdiRspParams, void* pUserData);
#ifdef WLAN_FEATURE_VOWIFI_11R
@@ -15302,6 +15307,266 @@ VOS_STATUS WDA_ProcessTLPauseInd(tWDA_CbContext *pWDA, v_U32_t params)
return WLANTL_SuspendDataTx(pWDA->pVosContext, &staId, NULL);
}
+/**
+ * WDA_SetARPStatsParamsRspCallback() - WDA callback api to set/reset arp stats
+ * @wdiSetStatsRsp: pointer to set stats response
+ * @user_data: user data
+ *
+ * Return: None
+ */
+void WDA_SetARPStatsParamsRspCallback(
+ WDI_SetARPStatsRspParamsType *wdiSetStatsRsp,
+ void *user_data)
+{
+ tWDA_ReqParams *wda_params = (tWDA_ReqParams *)user_data;
+ setArpStatsParams *arpStatsParams;
+
+ VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
+ "ENTER <------ %s " ,__func__);
+
+ if(NULL == wda_params)
+ {
+ VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
+ "%s: wda_params received NULL", __func__);
+ VOS_ASSERT(0);
+ return;
+ }
+
+ if(NULL == wda_params->wdaMsgParam)
+ {
+ VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
+ "%s: wda_params->wdaMsgParam is NULL", __func__);
+ VOS_ASSERT(0);
+ vos_mem_free(wda_params->wdaWdiApiMsgParam);
+ vos_mem_free(wda_params);
+ return;
+ }
+
+ arpStatsParams = (setArpStatsParams *)wda_params->wdaMsgParam;
+ if(arpStatsParams->rsp_cb_fn)
+ {
+ arpStatsParams->rsp_cb_fn(arpStatsParams->data_ctx,
+ CONVERT_WDI2VOS_STATUS(wdiSetStatsRsp->status));
+ }
+ else
+ {
+ VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
+ "%s: ARP stats callback is NULL", __func__);
+ }
+
+ vos_mem_free(wda_params->wdaWdiApiMsgParam);
+ vos_mem_free(wda_params->wdaMsgParam);
+ vos_mem_free(wda_params);
+ VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
+ "EXIT <------ %s " ,__func__);
+ return;
+}
+
+/**
+ * WDA_GetARPStatsParamsRspCallback() - WDA callback api to get arp stats
+ * @wdiGetStatsRsp: pointer to get stats response
+ * @user_data: user data
+ *
+ * Return: None
+ */
+void WDA_GetARPStatsParamsRspCallback(
+ WDI_GetARPStatsRspParamsType *wdiGetStatsRsp,
+ void *user_data)
+{
+ tWDA_ReqParams *wda_params = (tWDA_ReqParams *)user_data;
+ getArpStatsParams *arpStatsParams;
+
+ VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
+ "ENTER <------ %s " ,__func__);
+
+ if(NULL == wda_params)
+ {
+ VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
+ "%s: wda_params received NULL", __func__);
+ VOS_ASSERT(0);
+ return;
+ }
+
+ if(NULL == wda_params->wdaMsgParam)
+ {
+ VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
+ "%s: wda_params->wdaMsgParam is NULL", __func__);
+ VOS_ASSERT(0);
+ vos_mem_free(wda_params->wdaWdiApiMsgParam);
+ vos_mem_free(wda_params);
+ return;
+ }
+
+ arpStatsParams = (getArpStatsParams *)wda_params->wdaMsgParam;
+ if(arpStatsParams->get_rsp_cb_fn)
+ {
+ arpStatsParams->get_rsp_cb_fn(arpStatsParams->data_ctx,
+ (rsp_stats *)wdiGetStatsRsp);
+ }
+ else
+ {
+ VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
+ "%s: ARP stats callback is NULL", __func__);
+ }
+
+ vos_mem_free(wda_params->wdaWdiApiMsgParam);
+ vos_mem_free(wda_params->wdaMsgParam);
+ vos_mem_free(wda_params);
+ VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
+ "EXIT <------ %s " ,__func__);
+ return;
+}
+
+/**
+ * WDA_ProcessSetARPStatsReq() - WDA api to process set arp stats command
+ * @pWDA: wda handle
+ * @pSetStatsParams: pointer to set arp stats
+ *
+ * Return: VOS_STATUS
+ * 0 Success else failure
+ */
+VOS_STATUS WDA_ProcessSetARPStatsReq(tWDA_CbContext *pWDA,
+ setArpStatsParams *pSetStatsParams)
+{
+ WDI_SetARPStatsParamsInfoType *wdiSetStatsParam;
+ tWDA_ReqParams *wda_params;
+ WDI_Status wdi_status = WDI_STATUS_SUCCESS;
+
+ VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO,
+ FL("---> %s"), __func__);
+
+ if(NULL == pSetStatsParams)
+ {
+ VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
+ "%s: pSetStatsParams received NULL",
+ __func__);
+ VOS_ASSERT(0) ;
+ return VOS_STATUS_E_FAULT;
+ }
+
+ wdiSetStatsParam = (WDI_SetARPStatsParamsInfoType *)
+ vos_mem_malloc(sizeof(*wdiSetStatsParam));
+ if (!wdiSetStatsParam) {
+ VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
+ "Failed to allocate buffer to send "
+ "set_dhcp_server_offload cmd");
+ vos_mem_free(pSetStatsParams);
+ return VOS_STATUS_E_NOMEM;
+ }
+
+ vos_mem_zero(wdiSetStatsParam, sizeof(*wdiSetStatsParam));
+
+ wda_params = (tWDA_ReqParams *)vos_mem_malloc(sizeof(tWDA_ReqParams)) ;
+ if(NULL == wda_params)
+ {
+ VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
+ "%s: VOS MEM Alloc Failure", __func__);
+ VOS_ASSERT(0);
+ vos_mem_free(wdiSetStatsParam);
+ vos_mem_free(pSetStatsParams);
+ return VOS_STATUS_E_NOMEM;
+ }
+
+ wdiSetStatsParam->flag = pSetStatsParams->flag;
+ wdiSetStatsParam->pkt_type = pSetStatsParams->pkt_type;
+ wdiSetStatsParam->ip_addr = pSetStatsParams->ip_addr;
+
+ /* Store Params pass it to WDI */
+ wda_params->wdaWdiApiMsgParam = (void *)wdiSetStatsParam;
+ wda_params->pWdaContext = pWDA;
+ /* Store param pointer as passed in by caller */
+ wda_params->wdaMsgParam = pSetStatsParams;
+
+ wdi_status = WDI_SetARPStatsReq(wdiSetStatsParam,
+ (WDI_SetARPStatsRspCb)WDA_SetARPStatsParamsRspCallback,
+ wda_params);
+
+ if(IS_WDI_STATUS_FAILURE(wdi_status))
+ {
+ VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
+ "%s: Failure, free all the memory", __func__);
+ vos_mem_free(wda_params->wdaWdiApiMsgParam) ;
+ vos_mem_free(wda_params->wdaMsgParam);
+ vos_mem_free(wda_params);
+ }
+
+ return wdi_status;
+}
+
+/**
+ * WDA_ProcessGetARPStatsReq() - WDA api to process get arp stats command
+ * @pWDA: wda handle
+ * @pGetStatsParams: pointer to get arp stats
+ *
+ * Return: VOS_STATUS
+ * 0 Success else failure
+ */
+VOS_STATUS WDA_ProcessGetARPStatsReq(tWDA_CbContext *pWDA,
+ getArpStatsParams *pGetStatsParams)
+{
+ WDI_GetARPStatsParamsInfoType *wdiGetStatsParam;
+ tWDA_ReqParams *wda_params;
+ WDI_Status wdi_status = WDI_STATUS_SUCCESS;
+
+ VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO,
+ FL("---> %s"), __func__);
+
+ if(NULL == pGetStatsParams)
+ {
+ VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
+ "%s: pGetStatsParams received NULL",
+ __func__);
+ VOS_ASSERT(0) ;
+ return VOS_STATUS_E_FAULT;
+ }
+
+ wdiGetStatsParam = (WDI_GetARPStatsParamsInfoType *)
+ vos_mem_malloc(sizeof(*wdiGetStatsParam));
+ if (!wdiGetStatsParam) {
+ VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
+ "Failed to allocate buffer to send "
+ "set_dhcp_server_offload cmd");
+ vos_mem_free(pGetStatsParams);
+ return VOS_STATUS_E_NOMEM;
+ }
+
+ vos_mem_zero(wdiGetStatsParam, sizeof(*wdiGetStatsParam));
+
+ wda_params = (tWDA_ReqParams *)vos_mem_malloc(sizeof(tWDA_ReqParams)) ;
+ if(NULL == wda_params)
+ {
+ VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
+ "%s: VOS MEM Alloc Failure", __func__);
+ VOS_ASSERT(0);
+ vos_mem_free(wdiGetStatsParam);
+ vos_mem_free(pGetStatsParams);
+ return VOS_STATUS_E_NOMEM;
+ }
+
+ wdiGetStatsParam->pkt_type = pGetStatsParams->pkt_type;
+
+ /* Store Params pass it to WDI */
+ wda_params->wdaWdiApiMsgParam = (void *)wdiGetStatsParam;
+ wda_params->pWdaContext = pWDA;
+ /* Store param pointer as passed in by caller */
+ wda_params->wdaMsgParam = pGetStatsParams;
+
+ wdi_status = WDI_GetARPStatsReq(wdiGetStatsParam,
+ (WDI_GetARPStatsRspCb)WDA_GetARPStatsParamsRspCallback,
+ wda_params);
+
+ if(IS_WDI_STATUS_FAILURE(wdi_status))
+ {
+ VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
+ "%s: Failure, free all the memory", __func__);
+ vos_mem_free(wda_params->wdaWdiApiMsgParam) ;
+ vos_mem_free(wda_params->wdaMsgParam);
+ vos_mem_free(wda_params);
+ }
+
+ return wdi_status;
+}
+
/*
* FUNCTION: WDA_McProcessMsg
* Trigger DAL-AL to start CFG download
@@ -15924,16 +16189,26 @@ VOS_STATUS WDA_McProcessMsg( v_CONTEXT_t pVosContext, vos_msg_t *pMsg )
/* timer related messages */
case WDA_TIMER_BA_ACTIVITY_REQ:
{
- WDA_BaCheckActivity(pWDA) ;
+ WDA_BaCheckActivity(pWDA, false);
break ;
}
-
/* timer related messages */
case WDA_TIMER_TRAFFIC_STATS_IND:
{
WDA_TimerTrafficStatsInd(pWDA);
break;
}
+ /* Connection status related messages */
+ case WDA_TRIGGER_ADD_BA_REQ:
+ {
+ WDA_BaCheckActivity(pWDA, true);
+ break;
+ }
+ case WDA_GET_CON_STATUS:
+ {
+ WDA_GetConnectionStatus(pWDA, (getConStatusParams *)pMsg->bodyptr);
+ break;
+ }
#ifdef WLAN_FEATURE_VOWIFI_11R
case WDA_AGGR_QOS_REQ:
{
@@ -16290,6 +16565,16 @@ VOS_STATUS WDA_McProcessMsg( v_CONTEXT_t pVosContext, vos_msg_t *pMsg )
WDA_ProcessTLPauseInd(pWDA, pMsg->bodyval);
break;
}
+ case WDA_SET_ARP_STATS_REQ:
+ {
+ WDA_ProcessSetARPStatsReq(pWDA, (setArpStatsParams *)pMsg->bodyptr);
+ break;
+ }
+ case WDA_GET_ARP_STATS_REQ:
+ {
+ WDA_ProcessGetARPStatsReq(pWDA, (getArpStatsParams *)pMsg->bodyptr);
+ break;
+ }
default:
{
VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO,
@@ -17639,10 +17924,45 @@ bool WDA_AllowAddBA(tpAniSirGlobal pMac, tANI_U8 staId, tANI_U8 tid)
return true;
}
+void WDA_GetConnectionStatus(tWDA_CbContext *pWDA,
+ getConStatusParams *conStatusParams)
+{
+ tpAniSirGlobal pMac;
+ uint8_t sta_id, tid;
+ bool tx_aggr;
+ bool status = false;
+
+ pMac = (tpAniSirGlobal)VOS_GET_MAC_CTXT(pWDA->pVosContext);
+ if (NULL == pMac)
+ {
+ VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
+ "%s: pMac is NULL",__func__);
+ return;
+ }
+
+ tx_aggr= pMac->lim.test_status_bainfo.tx_aggr;
+ sta_id = pMac->lim.test_status_bainfo.sta_id;
+ tid = pMac->lim.test_status_bainfo.tid;
+
+ if (tx_aggr && WDA_GET_BA_TXFLAG(pWDA, sta_id, tid))
+ status = true;
+
+ if (conStatusParams->rsp_cb_fn)
+ conStatusParams->rsp_cb_fn(conStatusParams->data_ctx, status);
+}
+
+static void WDA_StoreTestBAInfo(tpAniSirGlobal pMac, bool tx_aggr,
+ uint8_t sta_id, uint8_t tid)
+{
+ pMac->lim.test_status_bainfo.tx_aggr = tx_aggr;
+ pMac->lim.test_status_bainfo.sta_id= sta_id;
+ pMac->lim.test_status_bainfo.tid = tid;
+}
+
/*
* BA Activity check timer handler
*/
-void WDA_BaCheckActivity(tWDA_CbContext *pWDA)
+void WDA_BaCheckActivity(tWDA_CbContext *pWDA, bool test_con)
{
tANI_U8 curSta = 0 ;
tANI_U8 tid = 0 ;
@@ -17652,6 +17972,7 @@ void WDA_BaCheckActivity(tWDA_CbContext *pWDA)
tANI_U32 val;
WDI_TriggerBAReqCandidateType baCandidate[WDA_MAX_STA] = {{0}} ;
tpAniSirGlobal pMac;
+ bool found = false;
if (NULL == pWDA)
{
@@ -17695,6 +18016,12 @@ void WDA_BaCheckActivity(tWDA_CbContext *pWDA)
for(curSta = 0 ; curSta < pWDA->wdaMaxSta ; curSta++)
{
tANI_U32 currentOperChan = pWDA->wdaStaInfo[curSta].currentOperChan;
+ WLANTL_STAStateType tlSTAState;
+ tANI_U8 validStaIndex = pWDA->wdaStaInfo[curSta].ucValidStaIndex;
+
+ if (found)
+ break;
+
#ifdef WLAN_SOFTAP_VSTA_FEATURE
// We can only do BA on "hard" STAs.
if (!(IS_HWSTA_IDX(curSta)))
@@ -17702,41 +18029,47 @@ void WDA_BaCheckActivity(tWDA_CbContext *pWDA)
continue;
}
#endif //WLAN_SOFTAP_VSTA_FEATURE
+
+ if (!((WDA_VALID_STA_INDEX == validStaIndex) &&
+ (VOS_STATUS_SUCCESS == WDA_TL_GET_STA_STATE(pWDA->pVosContext,
+ curSta, &tlSTAState))))
+ continue;
+
+ if (WLANTL_STA_AUTHENTICATED != tlSTAState)
+ continue;
+
+ if(val && ((currentOperChan >= SIR_11B_CHANNEL_BEGIN) &&
+ (currentOperChan <= SIR_11B_CHANNEL_END))) {
+ VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO,
+ "%s: BTC disabled aggregation - dont start"
+ "TX ADDBA req",__func__);
+ continue;
+ }
+
for(tid = 0 ; tid < STACFG_MAX_TC ; tid++)
{
- WLANTL_STAStateType tlSTAState ;
tANI_U32 txPktCount = 0 ;
- tANI_U8 validStaIndex = pWDA->wdaStaInfo[curSta].ucValidStaIndex ;
- if((WDA_VALID_STA_INDEX == validStaIndex) &&
- (VOS_STATUS_SUCCESS == WDA_TL_GET_STA_STATE( pWDA->pVosContext,
- curSta, &tlSTAState)) &&
- (VOS_STATUS_SUCCESS == WDA_TL_GET_TX_PKTCOUNT( pWDA->pVosContext,
- curSta, tid, &txPktCount)))
+ if (VOS_STATUS_SUCCESS == WDA_TL_GET_TX_PKTCOUNT( pWDA->pVosContext,
+ curSta, tid, &txPktCount))
{
-#if 0
- VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO_LOW,
- "************* %d:%d, %d ",curSta, txPktCount,
- pWDA->wdaStaInfo[curSta].framesTxed[tid]);
-#endif
- if(val && ( (currentOperChan >= SIR_11B_CHANNEL_BEGIN) &&
- (currentOperChan <= SIR_11B_CHANNEL_END)))
- {
- VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO,
- "%s: BTC disabled aggregation - dont start "
- "TX ADDBA req",__func__);
- }
- else if(!WDA_GET_BA_TXFLAG(pWDA, curSta, tid)
- && (WLANTL_STA_AUTHENTICATED == tlSTAState)
- && WDA_AllowAddBA(pMac, curSta, tid)
- && (((eSYSTEM_STA_IN_IBSS_ROLE ==
- pWDA->wdaGlobalSystemRole) && txPktCount )
- || (txPktCount >= WDA_LAST_POLLED_THRESHOLD(pWDA,
- curSta, tid))))
+ if(!WDA_GET_BA_TXFLAG(pWDA, curSta, tid) &&
+ WDA_AllowAddBA(pMac, curSta, tid) &&
+ (((eSYSTEM_STA_IN_IBSS_ROLE == pWDA->wdaGlobalSystemRole)
+ && txPktCount) ||
+ (txPktCount >= WDA_LAST_POLLED_THRESHOLD(pWDA, curSta, tid)) ||
+ test_con))
{
/* get prepare for sending message to HAL */
//baCandidate[baCandidateCount].staIdx = curSta ;
baCandidate[baCandidateCount].ucTidBitmap |= 1 << tid ;
newBaCandidate = WDA_ENABLE_BA ;
+
+ /* Trigger only one BA request to check connection status */
+ if (test_con) {
+ WDA_StoreTestBAInfo(pMac, true, curSta, tid);
+ found = true;
+ break;
+ }
}
pWDA->wdaStaInfo[curSta].framesTxed[tid] = txPktCount ;
}
@@ -17805,6 +18138,14 @@ void WDA_BaCheckActivity(tWDA_CbContext *pWDA)
}
else
{
+ if (test_con)
+ {
+ WDA_StoreTestBAInfo(pMac, false, pWDA->wdaMaxSta, STACFG_MAX_TC);
+ VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO,
+ "%s: ADDBA to test connection status no valid Tid found",
+ __func__);
+ }
+
VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO_LOW,
"There is no TID for initiating BA");
}
@@ -17824,6 +18165,7 @@ void WDA_BaCheckActivity(tWDA_CbContext *pWDA)
}
return ;
}
+
/*
* WDA common routine to create timer used by WDA.
*/
@@ -17907,6 +18249,7 @@ static VOS_STATUS wdaCreateTimers(tWDA_CbContext *pWDA)
}
return VOS_STATUS_SUCCESS ;
}
+
/*
* WDA common routine to destroy timer used by WDA.
*/
diff --git a/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda_ds.c b/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda_ds.c
index 2e303fb400d..b4a9bbba7e3 100644
--- a/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda_ds.c
+++ b/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda_ds.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2014, 2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2014, 2016-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@@ -436,6 +436,7 @@ WDA_DS_BuildTxPacketInfo
v_U32_t txFlag,
v_U32_t timeStamp,
v_U8_t ucIsEapol,
+ v_U8_t ucIsArp,
v_U8_t ucUP,
v_U32_t ucTxBdToken
)
@@ -497,6 +498,7 @@ WDA_DS_BuildTxPacketInfo
pTxMetaInfo->ac = ucUP;
pTxMetaInfo->fUP = uTid;
pTxMetaInfo->isEapol = ucIsEapol;
+ pTxMetaInfo->isArp = ucIsArp;
pTxMetaInfo->fdisableFrmXlt = ucDisableFrmXtl;
pTxMetaInfo->frmType = ( ( typeSubtype & 0x30 ) >> 4 );
pTxMetaInfo->typeSubtype = typeSubtype;
diff --git a/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi.h b/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi.h
index 6f0864d8af3..f76970efd8d 100644
--- a/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi.h
+++ b/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi.h
@@ -8449,6 +8449,9 @@ typedef void (*WDI_WifiConfigSetRspCb) (WDI_WifconfigSetRsp *wdiRsp, void *pUse
typedef void (*WDI_AntennaDivSelRspCb)(WDI_Status status,
void *resp, void *pUserData);
+typedef void (*wdi_nud_set_arp_rsp_cb)(void *event_data,void *user_data);
+typedef void (*wdi_nud_get_arp_rsp_cb)(void *event_data,void *user_data);
+
/*========================================================================
* Function Declarations and Documentation
==========================================================================*/
@@ -12237,4 +12240,54 @@ WDI_SetAllowedActionFramesInd(
);
void WDI_SetMgmtPktViaWQ5(wpt_boolean sendMgmtPktViaWQ5);
+
+/* ARP DEBUG STATS */
+typedef struct
+{
+ wpt_uint8 flag;
+ wpt_uint8 pkt_type;
+ wpt_uint32 ip_addr;
+} WDI_SetARPStatsParamsInfoType;
+
+typedef struct
+{
+ wpt_uint32 status;
+} WDI_SetARPStatsRspParamsType;
+
+typedef void (*WDI_SetARPStatsRspCb)(WDI_SetARPStatsRspParamsType* StatsRsp,
+ void* pUserData);
+
+WDI_Status
+WDI_SetARPStatsReq
+(
+ WDI_SetARPStatsParamsInfoType *pwdiSetStatsReqParams,
+ WDI_SetARPStatsRspCb wdiSetARPStatsRspCb,
+ void* pUserData
+);
+
+/* ARP DEBUG STATS */
+typedef struct
+{
+ wpt_uint8 pkt_type;
+} WDI_GetARPStatsParamsInfoType;
+
+typedef struct
+{
+ wpt_uint32 status;
+ wpt_uint16 dad;
+ wpt_uint16 tx_fw_cnt;
+ wpt_uint16 rx_fw_cnt;
+ wpt_uint16 tx_ack_cnt;
+} WDI_GetARPStatsRspParamsType;
+
+typedef void (*WDI_GetARPStatsRspCb)(WDI_GetARPStatsRspParamsType* StatsRsp,
+ void* pUserData);
+
+WDI_Status
+WDI_GetARPStatsReq
+(
+ WDI_GetARPStatsParamsInfoType *pwdiGetStatsReqParams,
+ WDI_GetARPStatsRspCb wdiGetARPStatsRspCb,
+ void* pUserData
+);
#endif /* #ifndef WLAN_QCT_WDI_H */
diff --git a/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi_bd.h b/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi_bd.h
index e42c1833a95..c828c4b2ea5 100644
--- a/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi_bd.h
+++ b/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi_bd.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2013, 2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, 2016-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@@ -1113,10 +1113,13 @@ typedef struct
This is filled by Host in Virgo 1.0 but it gets filled by ADU in
Virgo2.0/Libra. Queue ID */
wpt_uint32 queueId:5;
-
- wpt_uint32 reserved5:7;
+
+ wpt_uint32 isArp:1;
+
+ wpt_uint32 reserved5:6;
#else
- wpt_uint32 reserved5:7;
+ wpt_uint32 reserved5:6;
+ wpt_uint32 isArp:1;
wpt_uint32 queueId:5;
wpt_uint32 bdRate:2;
wpt_uint32 ap:2;
diff --git a/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi_dp.h b/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi_dp.h
index 465946ebae8..85446f1b6dd 100644
--- a/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi_dp.h
+++ b/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi_dp.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2014, 2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2014, 2016-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@@ -435,6 +435,7 @@ WDI_FillTxBd
wpt_uint8 ucProtMgmtFrame,
wpt_uint32 uTimeStamp,
wpt_uint8 isEapol,
+ wpt_uint8 isArp,
wpt_uint8* staIndex,
wpt_uint32 txBdToken
);
diff --git a/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi_i.h b/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi_i.h
index 7debb41ad07..4b74e41fbe3 100644
--- a/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi_i.h
+++ b/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi_i.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@@ -493,6 +493,9 @@ typedef enum
WDI_PER_ROAM_SCAN_OFFLOAD_REQ = 116,
WDI_PER_ROAM_SCAN_TRIGGER_REQ = 117,
#endif
+/* ARP DEBUG STATS */
+ WDI_FW_ARP_STATS_REQ = 118,
+ WDI_FW_GET_ARP_STATS_REQ = 119,
WDI_MAX_REQ,
@@ -870,6 +873,8 @@ typedef enum
WDI_PER_ROAM_SCAN_OFFLOAD_RSP = 116,
WDI_PER_ROAM_SCAN_TRIGGER_RSP = 117,
#endif
+ WDI_FW_ARP_STATS_RSP = 118,
+ WDI_FW_GET_ARP_STATS_RSP = 119,
/*-------------------------------------------------------------------------
Indications
@@ -6676,5 +6681,33 @@ WDI_ProcessSetAllowedActionFramesInd
WDI_ControlBlockType* pWDICtx,
WDI_EventInfoType* pEventData
);
+
+WDI_Status
+WDI_ProcessSetArpStatsReq
+(
+ WDI_ControlBlockType* pWDICtx,
+ WDI_EventInfoType* pEventData
+);
+
+WDI_Status
+WDI_ProcessSetArpStatsResp
+(
+ WDI_ControlBlockType* pWDICtx,
+ WDI_EventInfoType* pEventData
+);
+
+WDI_Status
+WDI_ProcessGetArpStatsReq
+(
+ WDI_ControlBlockType* pWDICtx,
+ WDI_EventInfoType* pEventData
+);
+
+WDI_Status
+WDI_ProcessGetArpStatsResp
+(
+ WDI_ControlBlockType* pWDICtx,
+ WDI_EventInfoType* pEventData
+);
#endif /*WLAN_QCT_WDI_I_H*/
diff --git a/drivers/staging/prima/CORE/WDI/CP/src/wlan_qct_wdi.c b/drivers/staging/prima/CORE/WDI/CP/src/wlan_qct_wdi.c
index 62acabfa049..b4dac6967b8 100644
--- a/drivers/staging/prima/CORE/WDI/CP/src/wlan_qct_wdi.c
+++ b/drivers/staging/prima/CORE/WDI/CP/src/wlan_qct_wdi.c
@@ -220,6 +220,11 @@ static placeHolderInCapBitmap supportEnabledFeatures[] =
,WIFI_CONFIG //61
,ANTENNA_DIVERSITY_SELECTION //62
,PER_BASED_ROAMING //63
+ ,FEATURE_NOT_SUPPORTED //64
+ ,FEATURE_NOT_SUPPORTED //65
+ ,FEATURE_NOT_SUPPORTED //66
+ ,FEATURE_NOT_SUPPORTED //67
+ ,NUD_DEBUG //68
};
/*--------------------------------------------------------------------------
@@ -516,6 +521,10 @@ WDI_ReqProcFuncType pfnReqProcTbl[WDI_MAX_UMAC_IND] =
NULL,
NULL,
#endif /* WLAN_FEATURE_ROAM_SCAN_OFFLOAD */
+
+ WDI_ProcessSetArpStatsReq, /* WDI_FW_ARP_STATS_REQ */
+ WDI_ProcessGetArpStatsReq, /* WDI_FW_GET_ARP_STATS_REQ */
+
/*-------------------------------------------------------------------------
Indications
-------------------------------------------------------------------------*/
@@ -837,6 +846,9 @@ WDI_RspProcFuncType pfnRspProcTbl[WDI_MAX_RESP] =
NULL,
NULL,
#endif
+/* ARP Debug Stats*/
+ WDI_ProcessSetArpStatsResp, /* WDI_FW_ARP_STATS_RSP */
+ WDI_ProcessGetArpStatsResp, /* WDI_FW_GET_ARP_STATS_RSP */
/*---------------------------------------------------------------------
Indications
---------------------------------------------------------------------*/
@@ -1297,6 +1309,11 @@ static char *WDI_getReqMsgString(wpt_uint16 wdiReqMsgId)
CASE_RETURN_STRING( WDI_ANTENNA_DIVERSITY_SELECTION_REQ );
CASE_RETURN_STRING( WDI_MODIFY_ROAM_PARAMS_IND );
CASE_RETURN_STRING( WDI_SET_ALLOWED_ACTION_FRAMES_IND );
+ CASE_RETURN_STRING( WDI_FW_ARP_STATS_REQ );
+ CASE_RETURN_STRING( WDI_FW_GET_ARP_STATS_REQ );
+#ifdef WLAN_FEATURE_APFIND
+ CASE_RETURN_STRING( WDI_SET_AP_FIND_IND );
+#endif
default:
return "Unknown WDI MessageId";
}
@@ -1305,6 +1322,84 @@ static char *WDI_getReqMsgString(wpt_uint16 wdiReqMsgId)
/**
+ * WDI_ProcessSetArpStatsResp() - WDI api to process set arp stats response
+ * @wdi_ctx: wdi context
+ * @event_data: event data
+ *
+ * Return: WDI_Status
+ */
+WDI_Status
+WDI_ProcessSetArpStatsResp
+(
+ WDI_ControlBlockType *wdi_ctx,
+ WDI_EventInfoType *event_data
+)
+{
+ wdi_nud_set_arp_rsp_cb nud_set_arp_rsp_callback;
+
+ WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_INFO,
+ "%s: Enter ", __func__);
+ /*-------------------------------------------------------------------
+ Sanity check
+ -----------------------------------------------------------------*/
+ if ((NULL == wdi_ctx) || (NULL == event_data) ||
+ (NULL == event_data->pEventData))
+ {
+ WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_WARN,
+ "%s: Invalid parameters", __func__);
+ WDI_ASSERT(0);
+ return WDI_STATUS_E_FAILURE;
+ }
+
+ nud_set_arp_rsp_callback =
+ (wdi_nud_set_arp_rsp_cb)wdi_ctx->pfncRspCB;
+
+ nud_set_arp_rsp_callback((void *) event_data->pEventData,
+ wdi_ctx->pRspCBUserData);
+
+ return WDI_STATUS_SUCCESS;
+}
+
+/**
+ * WDI_ProcessGetArpStatsResp() - WDI api to process get arp stats response
+ * @wdi_ctx: wdi context
+ * @event_data: event data
+ *
+ * Return: WDI_Status
+ */
+WDI_Status
+WDI_ProcessGetArpStatsResp
+(
+ WDI_ControlBlockType *wdi_ctx,
+ WDI_EventInfoType *event_data
+)
+{
+ wdi_nud_get_arp_rsp_cb nud_get_arp_rsp_callback;
+
+ WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_INFO,
+ "%s: Enter ", __func__);
+ /*-------------------------------------------------------------------
+ Sanity check
+ -----------------------------------------------------------------*/
+ if ((NULL == wdi_ctx) || (NULL == event_data) ||
+ (NULL == event_data->pEventData))
+ {
+ WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_WARN,
+ "%s: Invalid parameters", __func__);
+ WDI_ASSERT(0);
+ return WDI_STATUS_E_FAILURE;
+ }
+
+ nud_get_arp_rsp_callback =
+ (wdi_nud_get_arp_rsp_cb)wdi_ctx->pfncRspCB;
+
+ nud_get_arp_rsp_callback((void *) event_data->pEventData,
+ wdi_ctx->pRspCBUserData);
+
+ return WDI_STATUS_SUCCESS;
+}
+
+/**
@brief WDI_getRespMsgString prints the WDI resonse message in string.
@param wdiRespMsgId: WDI Message response Id
@@ -1641,6 +1736,11 @@ void WDI_TraceHostFWCapabilities(tANI_U32 *capabilityBitmap)
"%s", "PER_BASED_ROAMING");
pCapStr += strlen("PER_BASED_ROAMING");
break;
+ case NUD_DEBUG:
+ snprintf(pCapStr, sizeof("NUD_DEBUG"),
+ "%s", "NUD_DEBUG");
+ pCapStr += strlen("NUD_DEEBUG");
+ break;
}
*pCapStr++ = ',';
*pCapStr++ = ' ';
@@ -24750,6 +24850,10 @@ WDI_2_HAL_REQ_TYPE
case WDI_PER_ROAM_SCAN_TRIGGER_REQ:
return WLAN_HAL_PER_ROAM_SCAN_TRIGGER_REQ;
#endif
+ case WDI_FW_ARP_STATS_REQ:
+ return WLAN_HAL_FW_SET_CLEAR_ARP_STATS_REQ;
+ case WDI_FW_GET_ARP_STATS_REQ:
+ return WLAN_HAL_FW_GET_ARP_STATS_REQ;
default:
return WLAN_HAL_MSG_MAX;
}
@@ -25119,6 +25223,10 @@ case WLAN_HAL_DEL_STA_SELF_RSP:
case WLAN_HAL_PER_ROAM_SCAN_TRIGGER_RSP:
return WDI_PER_ROAM_SCAN_TRIGGER_RSP;
#endif
+ case WLAN_HAL_FW_SET_CLEAR_ARP_STATS_RSP:
+ return WDI_FW_ARP_STATS_RSP;
+ case WLAN_HAL_FW_GET_ARP_STATS_RSP:
+ return WDI_FW_GET_ARP_STATS_RSP;
default:
return eDRIVER_TYPE_MAX;
}
@@ -38195,3 +38303,211 @@ WDI_Status WDI_SetAllowedActionFramesInd(
return WDI_PostMainEvent(&gWDICb, WDI_REQUEST_EVENT, &wdiEventData);
}
+
+/**
+ * WDI_ProcessSetArpStatsReq() - WDI api to process arp stats request
+ * @pWDICtx: wdi context
+ * @pEventData: event data
+ *
+ * Return: WDI_Status
+ */
+WDI_Status
+WDI_ProcessSetArpStatsReq
+(
+ WDI_ControlBlockType* pWDICtx,
+ WDI_EventInfoType* pEventData
+)
+{
+ WDI_SetARPStatsParamsInfoType *pSetARPStatsReqParams;
+ WDI_SetARPStatsRspCb wdiSetARPStatsRspCb;
+ wpt_uint8* pSendBuffer;
+ wpt_uint16 usDataOffset;
+ wpt_uint16 usSendSize;
+ WDI_Status wdi_status;
+ tHalStatsArpReqMsg statsReqParams;
+
+ VOS_TRACE(VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_INFO,
+ "%s: %d Enter",__func__, __LINE__);
+
+ if (( NULL == pEventData ) || ( NULL == pEventData->pEventData) ||
+ ( NULL == pWDICtx ) )
+ {
+ WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_WARN,
+ "%s: Invalid parameters", __func__);
+ WDI_ASSERT(0);
+ return WDI_STATUS_E_FAILURE;
+ }
+
+ pSetARPStatsReqParams =
+ (WDI_SetARPStatsParamsInfoType *)pEventData->pEventData;
+ wdiSetARPStatsRspCb = (WDI_SetARPStatsRspCb)pEventData->pCBfnc;
+
+ if ((WDI_STATUS_SUCCESS != WDI_GetMessageBuffer(pWDICtx, WDI_FW_ARP_STATS_REQ,
+ sizeof(statsReqParams.statsArpReqParams),
+ &pSendBuffer, &usDataOffset, &usSendSize))||
+ ( usSendSize < (usDataOffset + sizeof(statsReqParams.statsArpReqParams))))
+ {
+ WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_WARN,
+ "Unable to get send buffer in set bss key req %p %p %p",
+ pEventData, pSetARPStatsReqParams, wdiSetARPStatsRspCb);
+ WDI_ASSERT(0);
+ return WDI_STATUS_E_FAILURE;
+ }
+
+ statsReqParams.statsArpReqParams.set_clr = pSetARPStatsReqParams->flag;
+ statsReqParams.statsArpReqParams.pkt_type =
+ pSetARPStatsReqParams->pkt_type;
+ statsReqParams.statsArpReqParams.ip_addr = pSetARPStatsReqParams->ip_addr;
+
+ wpalMemoryCopy( pSendBuffer+usDataOffset,
+ &statsReqParams.statsArpReqParams,
+ sizeof(statsReqParams.statsArpReqParams));
+
+ wdi_status = WDI_SendMsg(pWDICtx, pSendBuffer, usSendSize,
+ wdiSetARPStatsRspCb, pEventData->pUserData,
+ WDI_FW_ARP_STATS_RSP);
+
+ VOS_TRACE(VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_INFO,
+ "%s: %d Exit",__func__, __LINE__);
+ return wdi_status;
+}
+
+/**
+ * WDI_SetARPStatsReq() - WDI api to process set arp stats request
+ * @pwdiSetStatsReqParams: pointer to set stats params
+ * @wdiSetStatsRspCb: pointer to set response callback
+ * @pUserData: user data
+ *
+ * Return: WDI_Status
+ */
+WDI_Status
+WDI_SetARPStatsReq
+(
+ WDI_SetARPStatsParamsInfoType* pwdiSetStatsReqParams,
+ WDI_SetARPStatsRspCb wdiSetStatsRspCb,
+ void* pUserData
+)
+{
+ WDI_EventInfoType wdiEventData;
+
+ if (eWLAN_PAL_FALSE == gWDIInitialized )
+ {
+ WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR,
+ "WDI API call before module is initialized - Fail request");
+
+ return WDI_STATUS_E_NOT_ALLOWED;
+ }
+
+ wdiEventData.wdiRequest = WDI_FW_ARP_STATS_REQ;
+ wdiEventData.pEventData = pwdiSetStatsReqParams;
+ wdiEventData.uEventDataSize = sizeof(*pwdiSetStatsReqParams);
+ wdiEventData.pCBfnc = wdiSetStatsRspCb;
+ wdiEventData.pUserData = pUserData;
+
+ return WDI_PostMainEvent(&gWDICb, WDI_REQUEST_EVENT, &wdiEventData);
+
+}/*WDI_GetARPStatsReq*/
+
+/**
+ * WDI_ProcessGetArpStatsReq() - WDI api to process get arp stats request
+ * @pWDICtx: wdi context
+ * @pEventData: event data
+ *
+ * Return: WDI_Status
+ */
+WDI_Status
+WDI_ProcessGetArpStatsReq
+(
+ WDI_ControlBlockType* pWDICtx,
+ WDI_EventInfoType* pEventData
+)
+{
+ WDI_GetARPStatsParamsInfoType *pGetARPStatsReqParams;
+ WDI_GetARPStatsRspCb wdiGetARPStatsRspCb;
+ wpt_uint8* pSendBuffer;
+ wpt_uint16 usDataOffset;
+ wpt_uint16 usSendSize;
+ WDI_Status wdi_status;
+ tHalStatsGetArpReqMsg statsReqParams;
+
+ VOS_TRACE(VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_INFO,
+ "%s: %d Enter",__func__, __LINE__);
+
+ if (( NULL == pEventData ) || ( NULL == pEventData->pEventData) ||
+ ( NULL == pWDICtx ) )
+ {
+ WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_WARN,
+ "%s: Invalid parameters", __func__);
+ WDI_ASSERT(0);
+ return WDI_STATUS_E_FAILURE;
+ }
+
+ pGetARPStatsReqParams =
+ (WDI_GetARPStatsParamsInfoType *)pEventData->pEventData;
+ wdiGetARPStatsRspCb = (WDI_GetARPStatsRspCb)pEventData->pCBfnc;
+
+ if ((WDI_STATUS_SUCCESS != WDI_GetMessageBuffer(pWDICtx,
+ WDI_FW_GET_ARP_STATS_REQ,
+ sizeof(statsReqParams.statsGetArpReqParams),
+ &pSendBuffer, &usDataOffset, &usSendSize))||
+ ( usSendSize < (usDataOffset +
+ sizeof(statsReqParams.statsGetArpReqParams))))
+ {
+ WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_WARN,
+ "Unable to get send buffer in set bss key req %p %p %p",
+ pEventData, pGetARPStatsReqParams, wdiGetARPStatsRspCb);
+ WDI_ASSERT(0);
+ return WDI_STATUS_E_FAILURE;
+ }
+
+ statsReqParams.statsGetArpReqParams.pkt_type =
+ pGetARPStatsReqParams->pkt_type;
+
+ wpalMemoryCopy( pSendBuffer+usDataOffset,
+ &statsReqParams.statsGetArpReqParams,
+ sizeof(statsReqParams.statsGetArpReqParams));
+
+ wdi_status = WDI_SendMsg(pWDICtx, pSendBuffer, usSendSize,
+ wdiGetARPStatsRspCb, pEventData->pUserData,
+ WDI_FW_GET_ARP_STATS_RSP);
+
+ VOS_TRACE(VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_INFO,
+ "%s: %d Exit",__func__, __LINE__);
+ return wdi_status;
+}
+
+/**
+ * WDI_GetARPStatsReq() - WDI api to process get arp stats request
+ * @pwdiGetStatsReqParams: pointer to get stats params
+ * @wdiGetStatsRspCb: pointer to get response callback
+ * @pUserData: user data
+ *
+ * Return: WDI_Status
+ */
+WDI_Status
+WDI_GetARPStatsReq
+(
+ WDI_GetARPStatsParamsInfoType* pwdiGetStatsReqParams,
+ WDI_GetARPStatsRspCb wdiGetStatsRspCb,
+ void* pUserData
+)
+{
+ WDI_EventInfoType wdiEventData;
+
+ if (eWLAN_PAL_FALSE == gWDIInitialized )
+ {
+ WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR,
+ "WDI API call before module is initialized - Fail request");
+
+ return WDI_STATUS_E_NOT_ALLOWED;
+ }
+
+ wdiEventData.wdiRequest = WDI_FW_GET_ARP_STATS_REQ;
+ wdiEventData.pEventData = pwdiGetStatsReqParams;
+ wdiEventData.uEventDataSize = sizeof(*pwdiGetStatsReqParams);
+ wdiEventData.pCBfnc = wdiGetStatsRspCb;
+ wdiEventData.pUserData = pUserData;
+
+ return WDI_PostMainEvent(&gWDICb, WDI_REQUEST_EVENT, &wdiEventData);
+
+}/*WDI_GetARPStatsReq*/
diff --git a/drivers/staging/prima/CORE/WDI/CP/src/wlan_qct_wdi_dp.c b/drivers/staging/prima/CORE/WDI/CP/src/wlan_qct_wdi_dp.c
index 48bf139ff16..25d627f2388 100644
--- a/drivers/staging/prima/CORE/WDI/CP/src/wlan_qct_wdi_dp.c
+++ b/drivers/staging/prima/CORE/WDI/CP/src/wlan_qct_wdi_dp.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2014, 2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2014, 2016-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@@ -386,6 +386,7 @@ WDI_FillTxBd
wpt_uint8 ucProtMgmtFrame,
wpt_uint32 uTimeStamp,
wpt_uint8 isEapol,
+ wpt_uint8 isArp,
wpt_uint8* staIndex,
wpt_uint32 txBdToken
)
@@ -409,6 +410,9 @@ WDI_FillTxBd
Get type and subtype of the frame first
------------------------------------------------------------------------*/
pBd->txBdToken = txBdToken;
+
+ pBd->isArp = isArp;
+
ucType = (ucTypeSubtype & WDI_FRAME_TYPE_MASK) >> WDI_FRAME_TYPE_OFFSET;
ucSubType = (ucTypeSubtype & WDI_FRAME_SUBTYPE_MASK);
diff --git a/drivers/staging/prima/CORE/WDI/DP/inc/wlan_qct_wdi_ds.h b/drivers/staging/prima/CORE/WDI/DP/inc/wlan_qct_wdi_ds.h
index 483ad65980b..2acb5cec4cd 100644
--- a/drivers/staging/prima/CORE/WDI/DP/inc/wlan_qct_wdi_ds.h
+++ b/drivers/staging/prima/CORE/WDI/DP/inc/wlan_qct_wdi_ds.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2013, 2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, 2016-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@@ -53,11 +53,12 @@ typedef struct
wpt_uint32 txFlags;
wpt_uint8 ac;
wpt_uint8 isEapol:1; //0 - not eapol 1 - eapol
- wpt_uint8 isWai:1; //WAPI 0 - not WAI 1 WAI
+ wpt_uint8 isWai:1; //WAPI 0 - not WAI 1 WAI
+ wpt_uint8 isArp:1; //0 - not ARP 1 - ARP
wpt_uint8 fdisableFrmXlt:1; //0 - Let ADU do FT. 1 - bypass ADU FT
wpt_uint8 qosEnabled:1; //0 - non-Qos 1 - Qos
wpt_uint8 fenableWDS:1; //0 - not WDS 1 WDS
- wpt_uint8 reserved1:3;
+ wpt_uint8 reserved1:2;
wpt_uint8 typeSubtype;
wpt_uint8 fUP;
wpt_uint8 fSTAMACAddress[6];
diff --git a/drivers/staging/prima/CORE/WDI/DP/src/wlan_qct_wdi_ds.c b/drivers/staging/prima/CORE/WDI/DP/src/wlan_qct_wdi_ds.c
index 902c0de1f59..ac4512a83cd 100644
--- a/drivers/staging/prima/CORE/WDI/DP/src/wlan_qct_wdi_ds.c
+++ b/drivers/staging/prima/CORE/WDI/DP/src/wlan_qct_wdi_ds.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2013 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, 2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@@ -129,6 +129,7 @@ WDI_Status WDI_DS_TxPacket(void *pContext,
wpt_uint8 ucUP;
wpt_uint8 ucTypeSubtype;
wpt_uint8 isEapol;
+ wpt_uint8 isArp;
wpt_uint8 alignment;
wpt_uint32 ucTxFlag;
wpt_uint8 ucProtMgmtFrame;
@@ -160,6 +161,7 @@ WDI_Status WDI_DS_TxPacket(void *pContext,
ucTypeSubtype = pTxMetadata->typeSubtype;
ucUP = pTxMetadata->fUP;
isEapol = pTxMetadata->isEapol;
+ isArp = pTxMetadata->isArp;
ucTxFlag = pTxMetadata->txFlags;
ucProtMgmtFrame = pTxMetadata->fProtMgmtFrame;
pSTAMACAddress = &(pTxMetadata->fSTAMACAddress[0]);
@@ -211,9 +213,16 @@ WDI_Status WDI_DS_TxPacket(void *pContext,
WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_INFO,
"Packet Length is %d\n", pTxMetadata->fPktlen);
}
+
+ if (pTxMetadata->isArp)
+ {
+ WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_INFO,
+ "%s :Transmitting ARP packet",__func__);
+ }
+
wdiStatus = WDI_FillTxBd(pContext, ucTypeSubtype, pSTAMACAddress, pAddr2MACAddress,
- &ucUP, 1, pvBDHeader, ucTxFlag /* No ACK */, ucProtMgmtFrame, 0, isEapol, &staId,
- pTxMetadata->txBdToken);
+ &ucUP, 1, pvBDHeader, ucTxFlag /* No ACK */, ucProtMgmtFrame, 0, isEapol, isArp,
+ &staId, pTxMetadata->txBdToken);
if(WDI_STATUS_SUCCESS != wdiStatus)
{
diff --git a/drivers/staging/prima/CORE/WDI/TRP/DTS/src/wlan_qct_wdi_dts.c b/drivers/staging/prima/CORE/WDI/TRP/DTS/src/wlan_qct_wdi_dts.c
index 018b8be4f5e..a43656a1b41 100644
--- a/drivers/staging/prima/CORE/WDI/TRP/DTS/src/wlan_qct_wdi_dts.c
+++ b/drivers/staging/prima/CORE/WDI/TRP/DTS/src/wlan_qct_wdi_dts.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@@ -1259,6 +1259,13 @@ wpt_status WDTS_TxPacket(void *pContext, wpt_packet *pFrame)
#else
((pTxMetadata->isEapol) ? WDTS_CHANNEL_TX_HIGH_PRI : WDTS_CHANNEL_TX_LOW_PRI) : WDTS_CHANNEL_TX_HIGH_PRI;
#endif
+
+ if (pTxMetadata->isArp)
+ {
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
+ "%s :Transmitting ARP packet", __func__);
+ }
+
// Send packet to Transport Driver.
status = gTransportDriver.xmit(pDTDriverContext, pFrame, channel);
if ((WLAN_LOG_LEVEL_ACTIVE ==
diff --git a/drivers/staging/prima/CORE/WDI/WPAL/inc/wlan_qct_pal_api.h b/drivers/staging/prima/CORE/WDI/WPAL/inc/wlan_qct_pal_api.h
index c1a8d181233..aeacf6f58a0 100644
--- a/drivers/staging/prima/CORE/WDI/WPAL/inc/wlan_qct_pal_api.h
+++ b/drivers/staging/prima/CORE/WDI/WPAL/inc/wlan_qct_pal_api.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2015,2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@@ -389,4 +389,6 @@ int wpalIsDxeSSREnable(void);
wpt_uint8 wpalIsFwLoggingEnabled(void);
wpt_uint8 wpalIsFwLoggingSupported(void);
wpt_uint8 wpalIsFwEvLoggingEnabled(void);
+bool wpalIsArpPkt(void *pPacket);
+void wpalUpdateTXArpFWdeliveredStats(void);
#endif // __WLAN_QCT_PAL_API_H
diff --git a/drivers/staging/prima/CORE/WDI/WPAL/src/wlan_qct_pal_api.c b/drivers/staging/prima/CORE/WDI/WPAL/src/wlan_qct_pal_api.c
index 9e0f047fea4..ee70505da23 100644
--- a/drivers/staging/prima/CORE/WDI/WPAL/src/wlan_qct_pal_api.c
+++ b/drivers/staging/prima/CORE/WDI/WPAL/src/wlan_qct_pal_api.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012,2014-2015 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012,2014-2015,2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@@ -542,3 +542,20 @@ int wpalIsDxeSSREnable(void)
return vos_get_dxeSSREnable();
}
+bool wpalIsArpPkt(void *pPacket)
+{
+ vos_pkt_t *pkt = (vos_pkt_t*)pPacket;
+
+ if (vos_is_arp_pkt(pkt->pSkb, true))
+ {
+ if (vos_check_arp_req_target_ip(pkt->pSkb, true))
+ return true;
+ }
+
+ return false;
+}
+
+void wpalUpdateTXArpFWdeliveredStats(void)
+{
+ vos_update_arp_fw_tx_delivered();
+}
diff --git a/drivers/staging/prima/riva/inc/wlan_hal_msg.h b/drivers/staging/prima/riva/inc/wlan_hal_msg.h
index 581862c9307..a74f2e4e746 100644
--- a/drivers/staging/prima/riva/inc/wlan_hal_msg.h
+++ b/drivers/staging/prima/riva/inc/wlan_hal_msg.h
@@ -605,6 +605,11 @@ typedef enum
WLAN_HAL_PER_ROAM_SCAN_TRIGGER_REQ = 336,
WLAN_HAL_PER_ROAM_SCAN_TRIGGER_RSP = 337,
+ WLAN_HAL_FW_SET_CLEAR_ARP_STATS_REQ = 354,
+ WLAN_HAL_FW_SET_CLEAR_ARP_STATS_RSP = 355,
+ WLAN_HAL_FW_GET_ARP_STATS_REQ = 356,
+ WLAN_HAL_FW_GET_ARP_STATS_RSP = 357,
+
WLAN_HAL_MSG_MAX = WLAN_HAL_MSG_TYPE_MAX_ENUM_SIZE
}tHalHostMsgType;
@@ -6876,6 +6881,7 @@ typedef enum {
WIFI_CONFIG = 61,
ANTENNA_DIVERSITY_SELECTION = 62,
PER_BASED_ROAMING = 63,
+ NUD_DEBUG = 68,
MAX_FEATURE_SUPPORTED = 128,
} placeHolderInCapBitmap;
@@ -9302,6 +9308,69 @@ typedef PACKED_PRE struct PACKED_POST
tHalModifyRoamParamsIndParams modifyRoamParamsReqParams;
} tHalModifyRoamParamsInd, *tpHalModifyRoamParamsInd;
+/*---------------------------------------------------------------------------
+ * WLAN_HAL_FW_SET_CLEAR_ARP_STATS_REQ
+ *--------------------------------------------------------------------------*/
+typedef PACKED_PRE struct PACKED_POST
+{
+ tANI_U8 set_clr; /*1 set and 0 reset*/
+ tANI_U8 pkt_type; /* Default 1: ARP */
+ tANI_U32 ip_addr; /*GW ipv4 address */
+} tHalStatsArpReqParams, *tpHalStatsArpReqParams;
+
+typedef PACKED_PRE struct PACKED_POST
+{
+ tHalMsgHeader header;
+ tHalStatsArpReqParams statsArpReqParams;
+} tHalStatsArpReqMsg, *tpHalStatsArpReqMsg;
+
+/*---------------------------------------------------------------------------
+ * WLAN_HAL_FW_SET_CLEAR_ARP_STATS_RSP
+ *--------------------------------------------------------------------------*/
+typedef PACKED_PRE struct PACKED_POST
+{
+ tANI_U32 status; //success or failure
+} tHalStatsArpRspParams, *tpHalStatsArpRspParams;
+
+typedef PACKED_PRE struct PACKED_POST
+{
+ tHalMsgHeader header;
+ tHalStatsArpRspParams statsArpRspParams;
+} tHalStatsArpRspMsg, *tpHalStatsArpRspMsg;
+
+/*---------------------------------------------------------------------------
+ * WLAN_HAL_FW_GET_ARP_STATS_REQ
+ *--------------------------------------------------------------------------*/
+typedef PACKED_PRE struct PACKED_POST
+{
+ tANI_U8 pkt_type; /* Furture purpose */
+} tHalStatsGetArpReqParams, *tpHalStatsGetArpReqParams;
+
+typedef PACKED_PRE struct PACKED_POST
+{
+ tHalMsgHeader header;
+ tHalStatsGetArpReqParams statsGetArpReqParams;
+} tHalStatsGetArpReqMsg, *tpHalStatsGetArpReqMsg;
+
+/*---------------------------------------------------------------------------
+ * WLAN_HAL_FW_GET_ARP_STATS_RSP
+ *--------------------------------------------------------------------------*/
+typedef PACKED_PRE struct PACKED_POST
+{
+ tANI_U32 status;
+ tANI_U16 dad;
+ tANI_U16 arpReqRcvdInFW;
+ tANI_U16 ackedArpReqCnt;
+ tANI_U16 arpRspCnt;
+ tANI_U8 data[1];
+} tdbugArpStatsgetRspParams, *tpdbugArpStatsgetRspParams;
+
+typedef PACKED_PRE struct PACKED_POST
+{
+ tHalMsgHeader header;
+ tdbugArpStatsgetRspParams fwArpstatsRspParams;
+} tHalARPfwStatsRspMsg, *tpHalARPfwStatsRspMsg;
+
#if defined(__ANI_COMPILER_PRAGMA_PACK_STACK)
#pragma pack(pop)
#elif defined(__ANI_COMPILER_PRAGMA_PACK)
diff --git a/drivers/usb/phy/phy-ab8500-usb.c b/drivers/usb/phy/phy-ab8500-usb.c
index e5eb1b5a04e..2f261fba980 100644
--- a/drivers/usb/phy/phy-ab8500-usb.c
+++ b/drivers/usb/phy/phy-ab8500-usb.c
@@ -774,8 +774,6 @@ static int ab8500_usb_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, ab);
- ATOMIC_INIT_NOTIFIER_HEAD(&ab->phy.notifier);
-
/* all: Disable phy when called from set_host and set_peripheral */
INIT_WORK(&ab->phy_dis_work, ab8500_usb_phy_disable_work);
diff --git a/drivers/usb/phy/phy-gpio-vbus-usb.c b/drivers/usb/phy/phy-gpio-vbus-usb.c
index 8443335c2ea..f7451fa2778 100644
--- a/drivers/usb/phy/phy-gpio-vbus-usb.c
+++ b/drivers/usb/phy/phy-gpio-vbus-usb.c
@@ -314,8 +314,6 @@ static int __init gpio_vbus_probe(struct platform_device *pdev)
goto err_irq;
}
- ATOMIC_INIT_NOTIFIER_HEAD(&gpio_vbus->phy.notifier);
-
INIT_DELAYED_WORK(&gpio_vbus->work, gpio_vbus_work);
gpio_vbus->vbus_draw = regulator_get(&pdev->dev, "vbus_draw");
diff --git a/drivers/usb/phy/phy-mxs-usb.c b/drivers/usb/phy/phy-mxs-usb.c
index bd601c537c8..f2a77e236d0 100644
--- a/drivers/usb/phy/phy-mxs-usb.c
+++ b/drivers/usb/phy/phy-mxs-usb.c
@@ -157,8 +157,6 @@ static int mxs_phy_probe(struct platform_device *pdev)
mxs_phy->phy.notify_disconnect = mxs_phy_on_disconnect;
mxs_phy->phy.type = USB_PHY_TYPE_USB2;
- ATOMIC_INIT_NOTIFIER_HEAD(&mxs_phy->phy.notifier);
-
mxs_phy->clk = clk;
platform_set_drvdata(pdev, &mxs_phy->phy);
diff --git a/drivers/usb/phy/phy.c b/drivers/usb/phy/phy.c
index a9984c700d2..a3684f7908e 100644
--- a/drivers/usb/phy/phy.c
+++ b/drivers/usb/phy/phy.c
@@ -329,6 +329,8 @@ int usb_add_phy(struct usb_phy *x, enum usb_phy_type type)
return -EINVAL;
}
+ ATOMIC_INIT_NOTIFIER_HEAD(&x->notifier);
+
spin_lock_irqsave(&phy_lock, flags);
list_for_each_entry(phy, &phy_list, head) {
@@ -367,6 +369,8 @@ int usb_add_phy_dev(struct usb_phy *x)
return -EINVAL;
}
+ ATOMIC_INIT_NOTIFIER_HEAD(&x->notifier);
+
spin_lock_irqsave(&phy_lock, flags);
list_for_each_entry(phy_bind, &phy_bind_list, list)
if (!(strcmp(phy_bind->phy_dev_name, dev_name(x->dev))))