cnss_utils: Add support of cnss_utils for WLAN
Add support of cnss_utils for WLAN. Export APIs to WLAN host driver which are used to set/get WLAN related information. These information could be retrived later when WLAN driver is reloaded. CRs-Fixed: 2060693 Change-Id: I2c8c36602ec8af133946ff00c41ce648a2628041 Signed-off-by: Yuanyuan Liu <yuanliu@codeaurora.org>
This commit is contained in:
parent
ed7868840b
commit
e96a24d253
8 changed files with 361 additions and 0 deletions
|
@ -333,5 +333,6 @@ source "drivers/net/wireless/cw1200/Kconfig"
|
|||
source "drivers/net/wireless/rsi/Kconfig"
|
||||
source "drivers/net/wireless/cnss/Kconfig"
|
||||
source "drivers/net/wireless/cnss_genl/Kconfig"
|
||||
source "drivers/net/wireless/cnss_utils/Kconfig"
|
||||
|
||||
endif # WLAN
|
||||
|
|
|
@ -67,3 +67,4 @@ obj-$(CONFIG_CNSS) += cnss/
|
|||
obj-$(CONFIG_WCNSS_MEM_PRE_ALLOC) += cnss_prealloc/
|
||||
obj-$(CONFIG_CNSS_CRYPTO) += cnss_crypto/
|
||||
obj-$(CONFIG_CNSS_GENL) += cnss_genl/
|
||||
obj-$(CONFIG_CNSS_UTILS) += cnss_utils/
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
config CNSS
|
||||
tristate "CNSS driver for wifi module"
|
||||
select CNSS_UTILS
|
||||
select CRYPTO
|
||||
select CRYPTO_HASH
|
||||
select CRYPTO_BLKCIPHER
|
||||
|
|
6
drivers/net/wireless/cnss_utils/Kconfig
Normal file
6
drivers/net/wireless/cnss_utils/Kconfig
Normal file
|
@ -0,0 +1,6 @@
|
|||
config CNSS_UTILS
|
||||
bool "CNSS utilities support"
|
||||
---help---
|
||||
Add CNSS utilities support for the WLAN driver module.
|
||||
This feature enable wlan driver to use CNSS utilities APIs to set
|
||||
and get wlan related information.
|
1
drivers/net/wireless/cnss_utils/Makefile
Normal file
1
drivers/net/wireless/cnss_utils/Makefile
Normal file
|
@ -0,0 +1 @@
|
|||
obj-$(CONFIG_CNSS_UTILS) += cnss_utils.o
|
310
drivers/net/wireless/cnss_utils/cnss_utils.c
Normal file
310
drivers/net/wireless/cnss_utils/cnss_utils.c
Normal file
|
@ -0,0 +1,310 @@
|
|||
/* Copyright (c) 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
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "cnss_utils: " fmt
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <net/cnss_utils.h>
|
||||
|
||||
#define CNSS_MAX_CH_NUM 45
|
||||
struct cnss_unsafe_channel_list {
|
||||
u16 unsafe_ch_count;
|
||||
u16 unsafe_ch_list[CNSS_MAX_CH_NUM];
|
||||
};
|
||||
|
||||
struct cnss_dfs_nol_info {
|
||||
void *dfs_nol_info;
|
||||
u16 dfs_nol_info_len;
|
||||
};
|
||||
|
||||
#define MAX_NO_OF_MAC_ADDR 4
|
||||
struct cnss_wlan_mac_addr {
|
||||
u8 mac_addr[MAX_NO_OF_MAC_ADDR][ETH_ALEN];
|
||||
u32 no_of_mac_addr_set;
|
||||
};
|
||||
|
||||
static struct cnss_utils_priv {
|
||||
struct cnss_unsafe_channel_list unsafe_channel_list;
|
||||
struct cnss_dfs_nol_info dfs_nol_info;
|
||||
/* generic mutex for unsafe channel */
|
||||
struct mutex unsafe_channel_list_lock;
|
||||
/* generic spin-lock for dfs_nol info */
|
||||
spinlock_t dfs_nol_info_lock;
|
||||
int driver_load_cnt;
|
||||
bool is_wlan_mac_set;
|
||||
struct cnss_wlan_mac_addr wlan_mac_addr;
|
||||
enum cnss_utils_cc_src cc_source;
|
||||
} *cnss_utils_priv;
|
||||
|
||||
int cnss_utils_set_wlan_unsafe_channel(struct device *dev,
|
||||
u16 *unsafe_ch_list, u16 ch_count)
|
||||
{
|
||||
struct cnss_utils_priv *priv = cnss_utils_priv;
|
||||
|
||||
if (!priv)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&priv->unsafe_channel_list_lock);
|
||||
if ((!unsafe_ch_list) || (ch_count > CNSS_MAX_CH_NUM)) {
|
||||
mutex_unlock(&priv->unsafe_channel_list_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
priv->unsafe_channel_list.unsafe_ch_count = ch_count;
|
||||
|
||||
if (ch_count == 0)
|
||||
goto end;
|
||||
|
||||
memcpy(priv->unsafe_channel_list.unsafe_ch_list,
|
||||
unsafe_ch_list, ch_count * sizeof(u16));
|
||||
|
||||
end:
|
||||
mutex_unlock(&priv->unsafe_channel_list_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(cnss_utils_set_wlan_unsafe_channel);
|
||||
|
||||
int cnss_utils_get_wlan_unsafe_channel(struct device *dev,
|
||||
u16 *unsafe_ch_list,
|
||||
u16 *ch_count, u16 buf_len)
|
||||
{
|
||||
struct cnss_utils_priv *priv = cnss_utils_priv;
|
||||
|
||||
if (!priv)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&priv->unsafe_channel_list_lock);
|
||||
if (!unsafe_ch_list || !ch_count) {
|
||||
mutex_unlock(&priv->unsafe_channel_list_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (buf_len <
|
||||
(priv->unsafe_channel_list.unsafe_ch_count * sizeof(u16))) {
|
||||
mutex_unlock(&priv->unsafe_channel_list_lock);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
*ch_count = priv->unsafe_channel_list.unsafe_ch_count;
|
||||
memcpy(unsafe_ch_list, priv->unsafe_channel_list.unsafe_ch_list,
|
||||
priv->unsafe_channel_list.unsafe_ch_count * sizeof(u16));
|
||||
mutex_unlock(&priv->unsafe_channel_list_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(cnss_utils_get_wlan_unsafe_channel);
|
||||
|
||||
int cnss_utils_wlan_set_dfs_nol(struct device *dev,
|
||||
const void *info, u16 info_len)
|
||||
{
|
||||
void *temp;
|
||||
void *old_nol_info;
|
||||
struct cnss_dfs_nol_info *dfs_info;
|
||||
struct cnss_utils_priv *priv = cnss_utils_priv;
|
||||
|
||||
if (!priv)
|
||||
return -EINVAL;
|
||||
|
||||
if (!info || !info_len)
|
||||
return -EINVAL;
|
||||
|
||||
temp = kmalloc(info_len, GFP_ATOMIC);
|
||||
if (!temp)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(temp, info, info_len);
|
||||
spin_lock_bh(&priv->dfs_nol_info_lock);
|
||||
dfs_info = &priv->dfs_nol_info;
|
||||
old_nol_info = dfs_info->dfs_nol_info;
|
||||
dfs_info->dfs_nol_info = temp;
|
||||
dfs_info->dfs_nol_info_len = info_len;
|
||||
spin_unlock_bh(&priv->dfs_nol_info_lock);
|
||||
kfree(old_nol_info);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(cnss_utils_wlan_set_dfs_nol);
|
||||
|
||||
int cnss_utils_wlan_get_dfs_nol(struct device *dev,
|
||||
void *info, u16 info_len)
|
||||
{
|
||||
int len;
|
||||
struct cnss_dfs_nol_info *dfs_info;
|
||||
struct cnss_utils_priv *priv = cnss_utils_priv;
|
||||
|
||||
if (!priv)
|
||||
return -EINVAL;
|
||||
|
||||
if (!info || !info_len)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_bh(&priv->dfs_nol_info_lock);
|
||||
|
||||
dfs_info = &priv->dfs_nol_info;
|
||||
if (!dfs_info->dfs_nol_info ||
|
||||
dfs_info->dfs_nol_info_len == 0) {
|
||||
spin_unlock_bh(&priv->dfs_nol_info_lock);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
len = min(info_len, dfs_info->dfs_nol_info_len);
|
||||
memcpy(info, dfs_info->dfs_nol_info, len);
|
||||
spin_unlock_bh(&priv->dfs_nol_info_lock);
|
||||
|
||||
return len;
|
||||
}
|
||||
EXPORT_SYMBOL(cnss_utils_wlan_get_dfs_nol);
|
||||
|
||||
void cnss_utils_increment_driver_load_cnt(struct device *dev)
|
||||
{
|
||||
struct cnss_utils_priv *priv = cnss_utils_priv;
|
||||
|
||||
if (!priv)
|
||||
return;
|
||||
|
||||
++(priv->driver_load_cnt);
|
||||
}
|
||||
EXPORT_SYMBOL(cnss_utils_increment_driver_load_cnt);
|
||||
|
||||
int cnss_utils_get_driver_load_cnt(struct device *dev)
|
||||
{
|
||||
struct cnss_utils_priv *priv = cnss_utils_priv;
|
||||
|
||||
if (!priv)
|
||||
return -EINVAL;
|
||||
|
||||
return priv->driver_load_cnt;
|
||||
}
|
||||
EXPORT_SYMBOL(cnss_utils_get_driver_load_cnt);
|
||||
|
||||
int cnss_utils_set_wlan_mac_address(const u8 *in, const uint32_t len)
|
||||
{
|
||||
struct cnss_utils_priv *priv = cnss_utils_priv;
|
||||
u32 no_of_mac_addr;
|
||||
struct cnss_wlan_mac_addr *addr = NULL;
|
||||
int iter;
|
||||
u8 *temp = NULL;
|
||||
|
||||
if (!priv)
|
||||
return -EINVAL;
|
||||
|
||||
if (priv->is_wlan_mac_set) {
|
||||
pr_debug("WLAN MAC address is already set\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (len == 0 || (len % ETH_ALEN) != 0) {
|
||||
pr_err("Invalid length %d\n", len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
no_of_mac_addr = len / ETH_ALEN;
|
||||
if (no_of_mac_addr > MAX_NO_OF_MAC_ADDR) {
|
||||
pr_err("Exceed maximum supported MAC address %u %u\n",
|
||||
MAX_NO_OF_MAC_ADDR, no_of_mac_addr);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
priv->is_wlan_mac_set = true;
|
||||
addr = &priv->wlan_mac_addr;
|
||||
addr->no_of_mac_addr_set = no_of_mac_addr;
|
||||
temp = &addr->mac_addr[0][0];
|
||||
|
||||
for (iter = 0; iter < no_of_mac_addr;
|
||||
++iter, temp += ETH_ALEN, in += ETH_ALEN) {
|
||||
ether_addr_copy(temp, in);
|
||||
pr_debug("MAC_ADDR:%02x:%02x:%02x:%02x:%02x:%02x\n",
|
||||
temp[0], temp[1], temp[2],
|
||||
temp[3], temp[4], temp[5]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(cnss_utils_set_wlan_mac_address);
|
||||
|
||||
u8 *cnss_utils_get_wlan_mac_address(struct device *dev, uint32_t *num)
|
||||
{
|
||||
struct cnss_utils_priv *priv = cnss_utils_priv;
|
||||
struct cnss_wlan_mac_addr *addr = NULL;
|
||||
|
||||
if (!priv)
|
||||
goto out;
|
||||
|
||||
if (!priv->is_wlan_mac_set) {
|
||||
pr_debug("WLAN MAC address is not set\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
addr = &priv->wlan_mac_addr;
|
||||
*num = addr->no_of_mac_addr_set;
|
||||
return &addr->mac_addr[0][0];
|
||||
out:
|
||||
*num = 0;
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(cnss_utils_get_wlan_mac_address);
|
||||
|
||||
void cnss_utils_set_cc_source(struct device *dev,
|
||||
enum cnss_utils_cc_src cc_source)
|
||||
{
|
||||
struct cnss_utils_priv *priv = cnss_utils_priv;
|
||||
|
||||
if (!priv)
|
||||
return;
|
||||
|
||||
priv->cc_source = cc_source;
|
||||
}
|
||||
EXPORT_SYMBOL(cnss_utils_set_cc_source);
|
||||
|
||||
enum cnss_utils_cc_src cnss_utils_get_cc_source(struct device *dev)
|
||||
{
|
||||
struct cnss_utils_priv *priv = cnss_utils_priv;
|
||||
|
||||
if (!priv)
|
||||
return -EINVAL;
|
||||
|
||||
return priv->cc_source;
|
||||
}
|
||||
EXPORT_SYMBOL(cnss_utils_get_cc_source);
|
||||
|
||||
static int __init cnss_utils_init(void)
|
||||
{
|
||||
struct cnss_utils_priv *priv = NULL;
|
||||
|
||||
priv = kmalloc(sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->cc_source = CNSS_UTILS_SOURCE_CORE;
|
||||
|
||||
mutex_init(&priv->unsafe_channel_list_lock);
|
||||
spin_lock_init(&priv->dfs_nol_info_lock);
|
||||
|
||||
cnss_utils_priv = priv;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit cnss_utils_exit(void)
|
||||
{
|
||||
kfree(cnss_utils_priv);
|
||||
cnss_utils_priv = NULL;
|
||||
}
|
||||
|
||||
module_init(cnss_utils_init);
|
||||
module_exit(cnss_utils_exit);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DESCRIPTION(DEVICE "CNSS Utilities Driver");
|
|
@ -468,6 +468,7 @@ config MINIDUMP_MAX_ENTRIES
|
|||
|
||||
config ICNSS
|
||||
tristate "Platform driver for Q6 integrated connectivity"
|
||||
select CNSS_UTILS
|
||||
---help---
|
||||
This module adds support for Q6 integrated WLAN connectivity
|
||||
subsystem. This module is responsible for communicating WLAN on/off
|
||||
|
|
40
include/net/cnss_utils.h
Normal file
40
include/net/cnss_utils.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
/* Copyright (c) 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
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _CNSS_UTILS_H_
|
||||
#define _CNSS_UTILS_H_
|
||||
|
||||
enum cnss_utils_cc_src {
|
||||
CNSS_UTILS_SOURCE_CORE,
|
||||
CNSS_UTILS_SOURCE_11D,
|
||||
CNSS_UTILS_SOURCE_USER
|
||||
};
|
||||
|
||||
extern int cnss_utils_set_wlan_unsafe_channel(struct device *dev,
|
||||
u16 *unsafe_ch_list,
|
||||
u16 ch_count);
|
||||
extern int cnss_utils_get_wlan_unsafe_channel(struct device *dev,
|
||||
u16 *unsafe_ch_list,
|
||||
u16 *ch_count, u16 buf_len);
|
||||
extern int cnss_utils_wlan_set_dfs_nol(struct device *dev,
|
||||
const void *info, u16 info_len);
|
||||
extern int cnss_utils_wlan_get_dfs_nol(struct device *dev,
|
||||
void *info, u16 info_len);
|
||||
extern int cnss_utils_get_driver_load_cnt(struct device *dev);
|
||||
extern void cnss_utils_increment_driver_load_cnt(struct device *dev);
|
||||
extern int cnss_utils_set_wlan_mac_address(const u8 *in, uint32_t len);
|
||||
extern u8 *cnss_utils_get_wlan_mac_address(struct device *dev, uint32_t *num);
|
||||
extern void cnss_utils_set_cc_source(struct device *dev,
|
||||
enum cnss_utils_cc_src cc_source);
|
||||
extern enum cnss_utils_cc_src cnss_utils_get_cc_source(struct device *dev);
|
||||
|
||||
#endif
|
Loading…
Add table
Reference in a new issue