diff options
| author | Kaan Külahlı <kaankulahli@gmail.com> | 2017-05-25 19:54:16 +0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2017-05-25 19:54:16 +0300 |
| commit | 943acc22babac805296a8d6de42f424f8c00df5a (patch) | |
| tree | b710cb20d9b8c1e50a7705564ed08a968eb4c163 | |
| parent | 6f93f25b482cb3833bad393a2f4cde8a0d1a69ca (diff) | |
| parent | 14f0a97da192d0cf20ae234389925827d9c2c119 (diff) | |
pull request
68 files changed, 2898 insertions, 279 deletions
diff --git a/Documentation/ABI/testing/sysfs-devices-online b/Documentation/ABI/testing/sysfs-devices-online new file mode 100644 index 00000000000..f990026c074 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-devices-online @@ -0,0 +1,20 @@ +What: /sys/devices/.../online +Date: April 2013 +Contact: Rafael J. Wysocki <rafael.j.wysocki@intel.com> +Description: + The /sys/devices/.../online attribute is only present for + devices whose bus types provide .online() and .offline() + callbacks. The number read from it (0 or 1) reflects the value + of the device's 'offline' field. If that number is 1 and '0' + (or 'n', or 'N') is written to this file, the device bus type's + .offline() callback is executed for the device and (if + successful) its 'offline' field is updated accordingly. In + turn, if that number is 0 and '1' (or 'y', or 'Y') is written to + this file, the device bus type's .online() callback is executed + for the device and (if successful) its 'offline' field is + updated as appropriate. + + After a successful execution of the bus type's .offline() + callback the device cannot be used for any purpose until either + it is removed (i.e. device_del() is called for it), or its bus + type's .online() is exeucted successfully. diff --git a/arch/arm64/configs/zc550kl-custom_defconfig b/arch/arm64/configs/zc550kl-custom_defconfig index 6df7e4830d7..6b1e2df73da 100644 --- a/arch/arm64/configs/zc550kl-custom_defconfig +++ b/arch/arm64/configs/zc550kl-custom_defconfig @@ -552,7 +552,7 @@ CONFIG_MSM_PIL_MSS_QDSP6V5=y CONFIG_MSM_OCMEM=y CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y CONFIG_MSM_SCM=y -CONFIG_MSM_CORE_CTL=y +CONFIG_SCHED_CORE_CTL=y CONFIG_MSM_PERFORMANCE=y CONFIG_MEM_SHARE_QMI_SERVICE=y CONFIG_EXT2_FS=y diff --git a/arch/arm64/configs/zc550kl-perf_defconfig b/arch/arm64/configs/zc550kl-perf_defconfig index d5a2fc09657..9f5c9656514 100644 --- a/arch/arm64/configs/zc550kl-perf_defconfig +++ b/arch/arm64/configs/zc550kl-perf_defconfig @@ -490,7 +490,7 @@ CONFIG_MSM_PIL_MSS_QDSP6V5=y CONFIG_MSM_OCMEM=y CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y CONFIG_MSM_SCM=y -CONFIG_MSM_CORE_CTL=y +CONFIG_SCHED_CORE_CTL=y CONFIG_MSM_CORE_CTL_HELPER=y CONFIG_MSM_PERFORMANCE=y CONFIG_MEM_SHARE_QMI_SERVICE=y diff --git a/arch/arm64/configs/ze500kg-custom_defconfig b/arch/arm64/configs/ze500kg-custom_defconfig index 5f4fa66fc29..3294755dba5 100644 --- a/arch/arm64/configs/ze500kg-custom_defconfig +++ b/arch/arm64/configs/ze500kg-custom_defconfig @@ -557,7 +557,7 @@ CONFIG_MSM_PIL_MSS_QDSP6V5=y CONFIG_MSM_OCMEM=y CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y CONFIG_MSM_SCM=y -CONFIG_MSM_CORE_CTL=y +CONFIG_SCHED_CORE_CTL=y CONFIG_MSM_PERFORMANCE=y CONFIG_MEM_SHARE_QMI_SERVICE=y CONFIG_TEXURA_ARM64=y diff --git a/arch/arm64/configs/ze500kl-custom_defconfig b/arch/arm64/configs/ze500kl-custom_defconfig index f516da93cfb..4057f3194bc 100644 --- a/arch/arm64/configs/ze500kl-custom_defconfig +++ b/arch/arm64/configs/ze500kl-custom_defconfig @@ -555,7 +555,7 @@ CONFIG_MSM_PIL_MSS_QDSP6V5=y CONFIG_MSM_OCMEM=y CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y CONFIG_MSM_SCM=y -CONFIG_MSM_CORE_CTL=y +CONFIG_SCHED_CORE_CTL=y CONFIG_MSM_PERFORMANCE=y CONFIG_MEM_SHARE_QMI_SERVICE=y CONFIG_TEXURA_ARM64=y 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_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(¤t_image_rwsem); string_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE; + up_read(¤t_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(¤t_image_rwsem); + if (current_image != SMEM_IMAGE_VERSION_PARTITION_APPS) { + up_read(¤t_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(¤t_image_rwsem); return count; } store_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE; + up_read(¤t_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(¤t_image_rwsem); string_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE; + up_read(¤t_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(¤t_image_rwsem); + if (current_image != SMEM_IMAGE_VERSION_PARTITION_APPS) { + up_read(¤t_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(¤t_image_rwsem); return count; } store_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE; + up_read(¤t_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(¤t_image_rwsem); string_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE; + up_read(¤t_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(¤t_image_rwsem); + if (current_image != SMEM_IMAGE_VERSION_PARTITION_APPS) { + up_read(¤t_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(¤t_image_rwsem); return count; } store_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE; + up_read(¤t_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(¤t_image_rwsem); + ret = snprintf(buf, PAGE_SIZE, "%d\n", current_image); + up_read(¤t_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(¤t_image_rwsem); if (0 <= digit && digit < SMEM_IMAGE_VERSION_BLOCKS_COUNT) current_image = digit; else current_image = 0; + up_write(¤t_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)))) diff --git a/include/linux/compiler-gcc6.h b/include/linux/compiler-gcc6.h new file mode 100644 index 00000000000..622117be664 --- /dev/null +++ b/include/linux/compiler-gcc6.h @@ -0,0 +1,65 @@ +#ifndef __LINUX_COMPILER_H +#error "Please don't include <linux/compiler-gcc6.h> directly, include <linux/compiler.h> instead." +#endif + +#define __used __attribute__((__used__)) +#define __must_check __attribute__((warn_unused_result)) +#define __compiler_offsetof(a, b) __builtin_offsetof(a, b) + +/* Mark functions as cold. gcc will assume any path leading to a call + to them will be unlikely. This means a lot of manual unlikely()s + are unnecessary now for any paths leading to the usual suspects + like BUG(), printk(), panic() etc. [but let's keep them for now for + older compilers] + + Early snapshots of gcc 4.3 don't support this and we can't detect this + in the preprocessor, but we can live with this because they're unreleased. + Maketime probing would be overkill here. + + gcc also has a __attribute__((__hot__)) to move hot functions into + a special section, but I don't see any sense in this right now in + the kernel context */ +#define __cold __attribute__((__cold__)) + +#define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __COUNTER__) + +#ifndef __CHECKER__ +# define __compiletime_warning(message) __attribute__((warning(message))) +# define __compiletime_error(message) __attribute__((error(message))) +#endif /* __CHECKER__ */ + +/* + * Mark a position in code as unreachable. This can be used to + * suppress control flow warnings after asm blocks that transfer + * control elsewhere. + * + * Early snapshots of gcc 4.5 don't support this and we can't detect + * this in the preprocessor, but we can live with this because they're + * unreleased. Really, we need to have autoconf for the kernel. + */ +#define unreachable() __builtin_unreachable() + +/* Mark a function definition as prohibited from being cloned. */ +#define __noclone __attribute__((__noclone__)) + +/* + * Tell the optimizer that something else uses this function or variable. + */ +#define __visible __attribute__((externally_visible)) + +/* + * GCC 'asm goto' miscompiles certain code sequences: + * + * http://gcc.gnu.org/bugzilla/show_bug.cgi?id=58670 + * + * Work it around via a compiler barrier quirk suggested by Jakub Jelinek. + * + * (asm goto is automatically volatile - the naming reflects this.) + */ +#define asm_volatile_goto(x...) do { asm goto(x); asm (""); } while (0) + +#ifdef CONFIG_ARCH_USE_BUILTIN_BSWAP +#define __HAVE_BUILTIN_BSWAP32__ +#define __HAVE_BUILTIN_BSWAP64__ +#define __HAVE_BUILTIN_BSWAP16__ +#endif /* CONFIG_ARCH_USE_BUILTIN_BSWAP */ diff --git a/include/linux/device.h b/include/linux/device.h index 074d4503731..5ba4a30611e 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -72,6 +72,10 @@ extern void bus_remove_file(struct bus_type *, struct bus_attribute *); * the specific driver's probe to initial the matched device. * @remove: Called when a device removed from this bus. * @shutdown: Called at shut-down time to quiesce the device. + * + * @online: Called to put the device back online (after offlining it). + * @offline: Called to put the device offline for hot-removal. May fail. + * * @suspend: Called when a device on this bus wants to go to sleep mode. * @resume: Called to bring a device on this bus out of sleep mode. * @pm: Power management operations of this bus, callback the specific @@ -105,6 +109,9 @@ struct bus_type { int (*remove)(struct device *dev); void (*shutdown)(struct device *dev); + int (*online)(struct device *dev); + int (*offline)(struct device *dev); + int (*suspend)(struct device *dev, pm_message_t state); int (*resume)(struct device *dev); @@ -672,6 +679,8 @@ struct acpi_dev_node { * @release: Callback to free the device after all references have * gone away. This should be set by the allocator of the * device (i.e. the bus driver that discovered the device). + * @offline_disabled: If set, the device is permanently online. + * @offline: Set after successful invocation of bus type's .offline(). * * At the lowest level, every device in a Linux system is represented by an * instance of struct device. The device structure contains the information @@ -744,6 +753,9 @@ struct device { void (*release)(struct device *dev); struct iommu_group *iommu_group; + + bool offline_disabled:1; + bool offline:1; }; static inline struct device *kobj_to_dev(struct kobject *kobj) @@ -880,6 +892,15 @@ extern const char *device_get_devnode(struct device *dev, extern void *dev_get_drvdata(const struct device *dev); extern int dev_set_drvdata(struct device *dev, void *data); +static inline bool device_supports_offline(struct device *dev) +{ + return dev->bus && dev->bus->offline && dev->bus->online; +} + +extern void lock_device_hotplug(void); +extern void unlock_device_hotplug(void); +extern int device_offline(struct device *dev); +extern int device_online(struct device *dev); /* * Root device objects for grouping under /sys/devices */ diff --git a/init/Kconfig b/init/Kconfig index 6573f2c654d..f67913aea4f 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -1039,6 +1039,16 @@ config SCHED_HMP in their instructions per-cycle capability or the maximum frequency they can attain. +config SCHED_CORE_CTL + bool "QTI Core Control" + depends on SMP + help + This options enables the core control functionality in + the scheduler. Core control automatically offline and + online cores based on cpu load and utilization. + + If unsure, say N here. + config CHECKPOINT_RESTORE bool "Checkpoint/restore support" if EXPERT default n diff --git a/kernel/sched/Makefile b/kernel/sched/Makefile index 1c7bde63c5e..53ccd2f5d41 100644 --- a/kernel/sched/Makefile +++ b/kernel/sched/Makefile @@ -17,3 +17,4 @@ obj-$(CONFIG_SCHED_AUTOGROUP) += auto_group.o obj-$(CONFIG_SCHEDSTATS) += stats.o obj-$(CONFIG_SCHED_DEBUG) += debug.o obj-$(CONFIG_CGROUP_CPUACCT) += cpuacct.o +obj-$(CONFIG_SCHED_CORE_CTL) += core_ctl.o diff --git a/drivers/soc/qcom/core_ctl.c b/kernel/sched/core_ctl.c index 0148630a7e0..a1134c86d27 100644 --- a/drivers/soc/qcom/core_ctl.c +++ b/kernel/sched/core_ctl.c @@ -1,45 +1,24 @@ -/* - * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2016, 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 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 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. + * 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. */ -#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/sched/rt.h> #include <linux/mutex.h> #include <trace/events/power.h> @@ -81,6 +60,7 @@ struct cpu_data { struct task_struct *hotplug_thread; struct kobject kobj; struct list_head pending_lru; + bool disabled; }; static DEFINE_PER_CPU(struct cpu_data, cpu_state); @@ -200,6 +180,7 @@ static ssize_t store_busy_up_thres(struct cpu_data *state, 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]); @@ -231,6 +212,7 @@ static ssize_t store_busy_down_thres(struct cpu_data *state, 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]); @@ -307,19 +289,22 @@ static ssize_t show_global_state(struct cpu_data *state, char *buf) "\tIs busy: %u\n", c->is_busy); if (c->cpu != c->first_cpu) continue; - count += snprintf(buf + count, PAGE_SIZE- count, + 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); + count += snprintf(buf + count, PAGE_SIZE - count, + "\tStatus: %s\n", + c->disabled ? "disabled" : "enabled"); } return count; } static ssize_t store_not_preferred(struct cpu_data *state, - const char *buf, size_t count) + const char *buf, size_t count) { struct cpu_data *c; unsigned int i, first_cpu; @@ -359,6 +344,33 @@ static ssize_t show_not_preferred(struct cpu_data *state, char *buf) return count; } +static ssize_t store_disable(struct cpu_data *state, + const char *buf, size_t count) +{ + unsigned int val; + + if (sscanf(buf, "%u\n", &val) != 1) + return -EINVAL; + + val = !!val; + + if (state->disabled == val) + return count; + + state->disabled = val; + + if (!state->disabled) + wake_up_hotplug_thread(state); + + + return count; +} + +static ssize_t show_disable(struct cpu_data *state, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%u\n", state->disabled); +} + struct core_ctl_attr { struct attribute attr; ssize_t (*show)(struct cpu_data *, char *); @@ -385,6 +397,7 @@ core_ctl_attr_ro(need_cpus); core_ctl_attr_ro(online_cpus); core_ctl_attr_ro(global_state); core_ctl_attr_rw(not_preferred); +core_ctl_attr_rw(disable); static struct attribute *default_attrs[] = { &min_cpus.attr, @@ -399,6 +412,7 @@ static struct attribute *default_attrs[] = { &online_cpus.attr, &global_state.attr, ¬_preferred.attr, + &disable.attr, NULL }; @@ -445,7 +459,6 @@ static struct kobj_type ktype_core_ctl = { #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; @@ -460,7 +473,7 @@ static void update_running_avg(bool trigger_update) spin_lock_irqsave(&state_lock, flags); - now = core_ctl_get_time(); + now = ktime_to_ms(ktime_get()); if (now - rq_avg_timestamp_ms < rq_avg_period_ms - RQ_AVG_TOLERANCE) { spin_unlock_irqrestore(&state_lock, flags); return; @@ -570,7 +583,7 @@ static bool eval_need(struct cpu_data *f) need_flag = apply_limits(f, need_cpus) != apply_limits(f, f->need_cpus); last_need = f->need_cpus; - now = core_ctl_get_time(); + now = ktime_to_ms(ktime_get()); if (need_cpus == last_need) { f->need_ts = now; @@ -582,6 +595,7 @@ static bool eval_need(struct cpu_data *f) ret = 1; } else if (need_cpus < last_need) { s64 elapsed = now - f->need_ts; + if (elapsed >= f->offline_delay_ms) { ret = 1; } else { @@ -595,7 +609,8 @@ static bool eval_need(struct cpu_data *f) f->need_cpus = need_cpus; } - trace_core_ctl_eval_need(f->cpu, last_need, need_cpus, ret && need_flag); + trace_core_ctl_eval_need(f->cpu, last_need, need_cpus, + ret && need_flag); spin_unlock_irqrestore(&state_lock, flags); return ret && need_flag; @@ -642,6 +657,9 @@ static void wake_up_hotplug_thread(struct cpu_data *state) struct cpu_data *pcpu; bool no_wakeup = false; + if (unlikely(state->disabled)) + return; + for_each_possible_cpu(cpu) { pcpu = &per_cpu(cpu_state, cpu); if (cpu != pcpu->first_cpu) @@ -670,7 +688,7 @@ 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)) { + if (eval_need(state) && !state->disabled) { spin_lock_irqsave(&state->pending_lock, flags); state->pending = true; spin_unlock_irqrestore(&state->pending_lock, flags); @@ -679,6 +697,40 @@ static void core_ctl_timer_func(unsigned long cpu) } +static int core_ctl_online_core(unsigned int cpu) +{ + int ret; + struct device *dev; + + lock_device_hotplug(); + dev = get_cpu_device(cpu); + if (!dev) { + pr_err("%s: failed to get cpu%d device\n", __func__, cpu); + ret = -ENODEV; + } else { + ret = device_online(dev); + } + unlock_device_hotplug(); + return ret; +} + +static int core_ctl_offline_core(unsigned int cpu) +{ + int ret; + struct device *dev; + + lock_device_hotplug(); + dev = get_cpu_device(cpu); + if (!dev) { + pr_err("%s: failed to get cpu%d device\n", __func__, cpu); + ret = -ENODEV; + } else { + ret = device_offline(dev); + } + unlock_device_hotplug(); + return ret; +} + static void update_lru(struct cpu_data *f) { struct cpu_data *c, *tmp; @@ -719,7 +771,7 @@ static void __ref do_hotplug(struct cpu_data *f) continue; pr_debug("Trying to Offline CPU%u\n", c->cpu); - if (cpu_down(c->cpu)) + if (core_ctl_offline_core(c->cpu)) pr_debug("Unable to Offline CPU%u\n", c->cpu); } @@ -738,7 +790,7 @@ static void __ref do_hotplug(struct cpu_data *f) break; pr_debug("Trying to Offline CPU%u\n", c->cpu); - if (cpu_down(c->cpu)) + if (core_ctl_offline_core(c->cpu)) pr_debug("Unable to Offline CPU%u\n", c->cpu); } } else if (f->online_cpus < need) { @@ -850,7 +902,8 @@ static int __ref cpu_callback(struct notifier_block *nfb, * 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) { + if (!f->disabled && + apply_limits(f, f->need_cpus) <= f->online_cpus) { pr_debug("Prevent CPU%d onlining\n", cpu); ret = NOTIFY_BAD; } else { @@ -931,7 +984,6 @@ static struct notifier_block __refdata cpu_notifier = { /* ============================ init code ============================== */ -#define HOTPLUG_THREAD_NICE_VAL -7 static int group_init(struct cpumask *mask) { struct device *dev; @@ -939,11 +991,12 @@ static int group_init(struct cpumask *mask) struct cpu_data *f = &per_cpu(cpu_state, first_cpu); struct cpu_data *state; unsigned int cpu; + struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 }; if (likely(f->inited)) return 0; - dev = core_ctl_find_cpu_device(first_cpu); + dev = get_cpu_device(first_cpu); if (!dev) return -ENODEV; @@ -986,7 +1039,9 @@ static int group_init(struct cpumask *mask) f->hotplug_thread = kthread_run(try_hotplug, (void *) f, "core_ctl/%d", first_cpu); - set_user_nice(f->hotplug_thread, HOTPLUG_THREAD_NICE_VAL); + if (IS_ERR(f->hotplug_thread)) + return PTR_ERR(f->hotplug_thread); + sched_setscheduler_nocheck(f->hotplug_thread, SCHED_FIFO, ¶m); for_each_cpu(cpu, mask) { state = &per_cpu(cpu_state, cpu); @@ -1044,43 +1099,17 @@ static int __init core_ctl_init(void) init_timer_deferrable(&rq_avg_timer); rq_avg_timer.function = rq_avg_timer_func; - core_ctl_block_hotplug(); + get_online_cpus(); for_each_online_cpu(cpu) { - policy = core_ctl_get_policy(cpu); + policy = cpufreq_cpu_get(cpu); if (policy) { group_init(policy->related_cpus); - core_ctl_put_policy(policy); + cpufreq_cpu_put(policy); } } - core_ctl_unblock_hotplug(); + put_online_cpus(); 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"); +late_initcall(core_ctl_init); diff --git a/sound/soc/codecs/msm8x16-wcd.h b/sound/soc/codecs/msm8x16-wcd.h index 394bd8ec4f2..55c4f8353fc 100644 --- a/sound/soc/codecs/msm8x16-wcd.h +++ b/sound/soc/codecs/msm8x16-wcd.h @@ -36,6 +36,9 @@ #define MSM8X16_TOMBAK_LPASS_DIGCODEC_CBCR 0x0181C0B0 #define MSM8X16_TOMBAK_LPASS_DIGCODEC_AHB_CBCR 0x0181C0B4 +#define EXT_SPK_AMP_GPIO (902+121) +#define EXT_SPK_AMP_HEADSET_GPIO (902+8) + #define MSM8X16_CODEC_NAME "msm8x16_wcd_codec" #define MSM8X16_WCD_IS_DIGITAL_REG(reg) \ @@ -314,6 +317,8 @@ extern int msm8x16_wcd_hs_detect(struct snd_soc_codec *codec, extern void msm8x16_wcd_hs_detect_exit(struct snd_soc_codec *codec); +extern int msm8x16_wcd_restart_mbhc(struct snd_soc_codec *codec); + extern void msm8x16_wcd_spk_ext_pa_cb( int (*codec_spk_ext_pa)(struct snd_soc_codec *codec, int enable), struct snd_soc_codec *codec); diff --git a/sound/soc/codecs/wcd-mbhc-v2.h b/sound/soc/codecs/wcd-mbhc-v2.h index 500e474d2c9..e2cb79c0693 100644 --- a/sound/soc/codecs/wcd-mbhc-v2.h +++ b/sound/soc/codecs/wcd-mbhc-v2.h @@ -508,4 +508,6 @@ static inline int wcd_mbhc_get_impedance(struct wcd_mbhc *mbhc, } #endif void wcd_mbhc_deinit(struct wcd_mbhc *mbhc); +extern void msm8x16_wcd_codec_set_headset_state(u32 state); +extern int msm8x16_wcd_codec_get_headset_state(void); #endif /* __WCD_MBHC_V2_H__ */ |
