cnss2: Support dual wlan cards managed by cnss2 platform driver

Currently, the cnss2 platform driver just can support
one wlan device attached, so do the following change
to cover dual wlan card attach case. Firstly, delay
the second device go to pcie link suspend and power
off state to make sure it really finished the pcie
enumeration. Then pcie enumeration succeed with
multi-devices. Secondly, supporting to write the qrtr
node instance id to PCIE register for wlan fw reading,
which can fix qmi message exchange failure if active
two Hastings devices. Thirdly, change the usage of
plat_env to support dual Hastings.

Change-Id: Ica41a23d4e983b91c0ff1b4e76b380803fb877ab
Signed-off-by: Chaoli Zhou <zchaoli@codeaurora.org>
tirimbino
Chaoli Zhou 5 years ago
parent bdd6da44c0
commit bc5d30342b
  1. 6
      drivers/net/wireless/cnss2/Kconfig
  2. 10
      drivers/net/wireless/cnss2/debug.c
  3. 177
      drivers/net/wireless/cnss2/main.c
  4. 13
      drivers/net/wireless/cnss2/main.h
  5. 201
      drivers/net/wireless/cnss2/pci.c
  6. 15
      drivers/net/wireless/cnss2/qmi.c
  7. 1
      drivers/net/wireless/cnss2/qmi.h

@ -72,3 +72,9 @@ config CNSS_EMULATION
emulation hardware.
These changes are needed for WLAN drivers to support and meet the
requirement of emulation hardware.
config CNSS_SUPPORT_DUAL_DEV
bool "Enable cnss support dual wlan card"
---help---
This enables the changes from cnss platform driver to support dual
wlan card attach

@ -1,4 +1,4 @@
/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
/* Copyright (c) 2016-2020, 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
@ -681,8 +681,14 @@ int cnss_debugfs_create(struct cnss_plat_data *plat_priv)
{
int ret = 0;
struct dentry *root_dentry;
char name[15];
if (cnss_get_dual_wlan())
snprintf(name, sizeof(name), "cnss_%d", plat_priv->idx);
else
snprintf(name, sizeof(name), "cnss");
root_dentry = debugfs_create_dir(name, NULL);
root_dentry = debugfs_create_dir("cnss", 0);
if (IS_ERR(root_dentry)) {
ret = PTR_ERR(root_dentry);
cnss_pr_err("Unable to create debugfs %d\n", ret);

@ -47,7 +47,20 @@
#define CNSS_QMI_TIMEOUT_DEFAULT 10000
#define CNSS_BDF_TYPE_DEFAULT CNSS_BDF_ELF
#ifdef CONFIG_CNSS_SUPPORT_DUAL_DEV
#define CNSS_DUAL_WLAN 1
#else
#define CNSS_DUAL_WLAN 0
#endif
#ifdef CONFIG_CNSS_SUPPORT_DUAL_DEV
static struct cnss_plat_data *plat_env[CNSS_MAX_DEV_NUM];
static int plat_env_count;
#else
static struct cnss_plat_data *plat_env;
#endif
static bool pm_notify_registered;
static DECLARE_RWSEM(cnss_pm_sem);
@ -70,6 +83,80 @@ struct cnss_driver_event {
void *data;
};
#ifdef CONFIG_CNSS_SUPPORT_DUAL_DEV
static void cnss_set_plat_priv(struct platform_device *plat_dev,
struct cnss_plat_data *plat_priv)
{
cnss_pr_dbg("Set plat_priv at %d", plat_env_count);
if (plat_priv) {
plat_priv->idx = plat_env_count;
plat_env[plat_priv->idx] = plat_priv;
plat_env_count++;
}
}
struct cnss_plat_data *cnss_get_plat_priv(struct platform_device
*plat_dev)
{
int i;
if (!plat_dev)
return NULL;
for (i = 0; i < plat_env_count; i++) {
if (plat_env[i]->plat_dev == plat_dev)
return plat_env[i];
}
return NULL;
}
static void cnss_clear_plat_priv(struct cnss_plat_data *plat_priv)
{
cnss_pr_dbg("Clear plat_priv at %d", plat_priv->idx);
plat_env[plat_priv->idx] = NULL;
plat_env_count--;
}
static int cnss_set_device_name(struct cnss_plat_data *plat_priv)
{
snprintf(plat_priv->device_name, sizeof(plat_priv->device_name),
"wlan_%d", plat_priv->idx);
return 0;
}
static int cnss_plat_env_available(void)
{
int ret = 0;
if (plat_env_count >= CNSS_MAX_DEV_NUM) {
cnss_pr_err("ERROR: No space to store plat_priv\n");
ret = -ENOMEM;
}
return ret;
}
int cnss_get_plat_env_count(void)
{
return plat_env_count;
}
struct cnss_plat_data *cnss_get_plat_env(int index)
{
return plat_env[index];
}
struct cnss_plat_data *cnss_get_plat_priv_by_rc_num(int rc_num)
{
int i;
for (i = 0; i < plat_env_count; i++) {
if (plat_env[i]->rc_num == rc_num)
return plat_env[i];
}
return NULL;
}
#else
static void cnss_set_plat_priv(struct platform_device *plat_dev,
struct cnss_plat_data *plat_priv)
{
@ -81,6 +168,35 @@ struct cnss_plat_data *cnss_get_plat_priv(struct platform_device *plat_dev)
return plat_env;
}
static void cnss_clear_plat_priv(struct cnss_plat_data *plat_priv)
{
plat_env = NULL;
}
static int cnss_set_device_name(struct cnss_plat_data *plat_priv)
{
snprintf(plat_priv->device_name, sizeof(plat_priv->device_name),
"wlan");
return 0;
}
static int cnss_plat_env_available(void)
{
return 0;
}
struct cnss_plat_data *cnss_get_plat_priv_by_rc_num(int rc_num)
{
return cnss_bus_dev_to_plat_priv(NULL);
}
#endif
bool cnss_get_dual_wlan(void)
{
return CNSS_DUAL_WLAN;
}
static int cnss_pm_notify(struct notifier_block *b,
unsigned long event, void *p)
{
@ -1550,7 +1666,7 @@ int cnss_register_subsys(struct cnss_plat_data *plat_priv)
subsys_info = &plat_priv->subsys_info;
subsys_info->subsys_desc.name = "wlan";
subsys_info->subsys_desc.name = plat_priv->device_name;
subsys_info->subsys_desc.owner = THIS_MODULE;
subsys_info->subsys_desc.powerup = cnss_subsys_powerup;
subsys_info->subsys_desc.shutdown = cnss_subsys_shutdown;
@ -1926,7 +2042,10 @@ static int cnss_misc_init(struct cnss_plat_data *plat_priv)
setup_timer(&plat_priv->fw_boot_timer, cnss_bus_fw_boot_timeout_hdlr,
(unsigned long)plat_priv);
register_pm_notifier(&cnss_pm_notifier);
if (!pm_notify_registered) {
register_pm_notifier(&cnss_pm_notifier);
pm_notify_registered = true;
}
ret = device_init_wakeup(&plat_priv->plat_dev->dev, true);
if (ret)
@ -1949,7 +2068,10 @@ static void cnss_misc_deinit(struct cnss_plat_data *plat_priv)
complete_all(&plat_priv->cal_complete);
complete_all(&plat_priv->power_up_complete);
device_init_wakeup(&plat_priv->plat_dev->dev, false);
unregister_pm_notifier(&cnss_pm_notifier);
if (pm_notify_registered) {
unregister_pm_notifier(&cnss_pm_notifier);
pm_notify_registered = false;
}
del_timer(&plat_priv->fw_boot_timer);
}
@ -2042,6 +2164,20 @@ cnss_is_converged_dt(struct cnss_plat_data *plat_priv)
"qcom,converged-dt");
}
static inline int
cnss_get_rc_num(struct cnss_plat_data *plat_priv)
{
return of_property_read_u32(plat_priv->plat_dev->dev.of_node,
"qcom,wlan-rc-num", &plat_priv->rc_num);
}
static inline int
cnss_get_qrtr_node_id(struct cnss_plat_data *plat_priv)
{
return of_property_read_u32(plat_priv->plat_dev->dev.of_node,
"qcom,qrtr_node_id", &plat_priv->qrtr_node_id);
}
static int cnss_probe(struct platform_device *plat_dev)
{
int ret = 0;
@ -2054,6 +2190,9 @@ static int cnss_probe(struct platform_device *plat_dev)
ret = -EEXIST;
goto out;
}
ret = cnss_plat_env_available();
if (ret != 0)
goto out;
of_id = of_match_device(cnss_of_match_table, &plat_dev->dev);
if (!of_id || !of_id->data) {
@ -2074,12 +2213,31 @@ static int cnss_probe(struct platform_device *plat_dev)
plat_priv->plat_dev = plat_dev;
plat_priv->dev_node = NULL;
plat_priv->device_id = device_id->driver_data;
ret = cnss_get_rc_num(plat_priv);
if (ret)
cnss_pr_err("Failed to find PCIe RC number, err = %d\n", ret);
cnss_pr_dbg("%s: rc_num=%d\n", __func__, plat_priv->rc_num);
ret = cnss_get_qrtr_node_id(plat_priv);
if (ret) {
cnss_pr_dbg("Failed to find qrtr_node_id err=%d\n", ret);
plat_priv->qrtr_node_id = 0;
plat_priv->wlfw_service_instance_id = 0;
} else {
plat_priv->wlfw_service_instance_id = plat_priv->qrtr_node_id +
FW_ID_BASE;
cnss_pr_dbg("service_instance_id=0x%x\n",
plat_priv->wlfw_service_instance_id);
}
plat_priv->is_converged_dt = cnss_is_converged_dt(plat_priv);
cnss_pr_dbg("Probing platform driver from %s DT\n",
plat_priv->is_converged_dt ? "converged" : "single");
plat_priv->bus_type = cnss_get_bus_type(plat_priv);
cnss_set_plat_priv(plat_dev, plat_priv);
cnss_set_device_name(plat_priv);
platform_set_drvdata(plat_dev, plat_priv);
INIT_LIST_HEAD(&plat_priv->vreg_list);
@ -2128,10 +2286,6 @@ static int cnss_probe(struct platform_device *plat_dev)
if (ret)
goto destroy_debugfs;
ret = cnss_genl_init();
if (ret < 0)
cnss_pr_err("CNSS genl init failed %d\n", ret);
cnss_pr_info("Platform driver probed successfully.\n");
return 0;
@ -2158,7 +2312,7 @@ free_res:
cnss_put_resources(plat_priv);
reset_ctx:
platform_set_drvdata(plat_dev, NULL);
cnss_set_plat_priv(plat_dev, NULL);
cnss_clear_plat_priv(plat_priv);
out:
return ret;
}
@ -2167,7 +2321,6 @@ static int cnss_remove(struct platform_device *plat_dev)
{
struct cnss_plat_data *plat_priv = platform_get_drvdata(plat_dev);
cnss_genl_exit();
cnss_misc_deinit(plat_priv);
cnss_debugfs_destroy(plat_priv);
cnss_qmi_deinit(plat_priv);
@ -2178,7 +2331,7 @@ static int cnss_remove(struct platform_device *plat_dev)
cnss_bus_deinit(plat_priv);
cnss_put_resources(plat_priv);
platform_set_drvdata(plat_dev, NULL);
plat_env = NULL;
cnss_clear_plat_priv(plat_priv);
return 0;
}
@ -2204,6 +2357,9 @@ static int __init cnss_initialize(void)
ret = platform_driver_register(&cnss_platform_driver);
if (ret)
cnss_debug_deinit();
ret = cnss_genl_init();
if (ret < 0)
cnss_pr_err("CNSS genl init failed %d\n", ret);
return ret;
}
@ -2212,6 +2368,7 @@ static void __exit cnss_exit(void)
{
platform_driver_unregister(&cnss_platform_driver);
cnss_debug_deinit();
cnss_genl_exit();
}
module_init(cnss_initialize);

@ -37,6 +37,8 @@
#define CNSS_FW_PATH_MAX_LEN 32
#define CNSS_MAX_DEV_NUM 2
enum cnss_dev_bus_type {
CNSS_BUS_NONE = -1,
CNSS_BUS_PCI,
@ -320,9 +322,20 @@ struct cnss_plat_data {
u8 set_wlaon_pwr_ctrl;
bool fw_pcie_gen_switch;
u8 pcie_gen_speed;
u32 rc_num;
char device_name[16];
u32 idx;
bool enumerate_done;
int qrtr_node_id;
unsigned int wlfw_service_instance_id;
};
struct cnss_plat_data *cnss_get_plat_priv(struct platform_device *plat_dev);
struct cnss_plat_data *cnss_get_plat_priv_by_rc_num(int rc_num);
int cnss_get_plat_env_count(void);
struct cnss_plat_data *cnss_get_plat_env(int index);
bool cnss_get_dual_wlan(void);
int cnss_driver_event_post(struct cnss_plat_data *plat_priv,
enum cnss_driver_event_type type,
u32 flags, void *data);

@ -60,6 +60,8 @@
#define EMULATION_HW 0
#endif
static bool cnss_driver_registered;
static DEFINE_SPINLOCK(pci_link_down_lock);
static DEFINE_SPINLOCK(pci_reg_window_lock);
@ -137,6 +139,7 @@ static DEFINE_SPINLOCK(pci_reg_window_lock);
#define FORCE_WAKE_DELAY_TIMEOUT_US 60000
#define QCA6390_WLAON_QFPROM_PWR_CTRL_REG 0x1F8031C
#define QCA6390_PCIE_SCRATCH_0_SOC_PCIE_REG 0x1E04040
#define POWER_ON_RETRY_MAX_TIMES 3
#define POWER_ON_RETRY_DELAY_MS 200
@ -1236,13 +1239,72 @@ int cnss_pci_is_drv_connected(struct device *dev)
}
EXPORT_SYMBOL(cnss_pci_is_drv_connected);
#ifdef CONFIG_CNSS_SUPPORT_DUAL_DEV
static struct cnss_plat_data *cnss_get_plat_priv_by_driver_ops(
struct cnss_wlan_driver *driver_ops)
{
int plat_env_count = cnss_get_plat_env_count();
struct cnss_plat_data *plat_env;
struct cnss_pci_data *pci_priv;
int i = 0;
if (!driver_ops) {
cnss_pr_err("No cnss driver\n");
return NULL;
}
for (i = 0; i < plat_env_count; i++) {
plat_env = cnss_get_plat_env(i);
if (!plat_env)
continue;
pci_priv = plat_env->bus_priv;
if (!pci_priv) {
cnss_pr_err("pci_priv is NULL\n");
continue;
}
if (driver_ops == pci_priv->driver_ops)
return plat_env;
}
/* Doesn't find the existing instance,
* so return the fist empty instance
*/
for (i = 0; i < plat_env_count; i++) {
plat_env = cnss_get_plat_env(i);
if (!plat_env)
continue;
pci_priv = plat_env->bus_priv;
if (!pci_priv) {
cnss_pr_err("pci_priv is NULL\n");
continue;
}
if (!pci_priv->driver_ops)
return plat_env;
}
return NULL;
}
#else
static struct cnss_plat_data *cnss_get_plat_priv_by_driver_ops(
struct cnss_wlan_driver *driver_ops)
{
return cnss_bus_dev_to_plat_priv(NULL);
}
#endif
int cnss_wlan_register_driver(struct cnss_wlan_driver *driver_ops)
{
int ret = 0;
struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(NULL);
struct cnss_plat_data *plat_priv;
struct cnss_pci_data *pci_priv;
unsigned int timeout;
plat_priv = cnss_get_plat_priv_by_driver_ops(driver_ops);
if (!plat_priv) {
cnss_pr_err("plat_priv is NULL\n");
return -ENODEV;
@ -1286,9 +1348,10 @@ EXPORT_SYMBOL(cnss_wlan_register_driver);
void cnss_wlan_unregister_driver(struct cnss_wlan_driver *driver_ops)
{
struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(NULL);
struct cnss_plat_data *plat_priv;
int ret = 0;
plat_priv = cnss_get_plat_priv_by_driver_ops(driver_ops);
if (!plat_priv) {
cnss_pr_err("plat_priv is NULL\n");
return;
@ -3216,6 +3279,44 @@ int cnss_pci_start_mhi(struct cnss_pci_data *pci_priv)
if (ret)
goto out;
/**
* in the single wlan chipset case, plat_priv->qrtr_node_id always is 0,
* wlan fw will use the hardcode 7 as the qrtr node id.
* in the dual Hastings case, we will read qrtr node id
* from device tree and pass to get plat_priv->qrtr_node_id,
* which always is not zero. And then store this new value
* to pcie register, wlan fw will read out this qrtr node id
* from this register and overwrite to the hardcode one
* while do initialization for ipc router.
* without this change, two Hastings will use the same
* qrtr node instance id, which will mess up qmi message
* exchange. According to qrtr spec, every node should
* have unique qrtr node id
*/
if (plat_priv->device_id == QCA6390_DEVICE_ID &&
plat_priv->qrtr_node_id) {
u32 val;
cnss_pr_dbg("write 0x%x to QCA6390_PCIE_SCRATCH_0_SOC_PCIE_REG\n",
plat_priv->qrtr_node_id);
ret = cnss_pci_reg_write(pci_priv,
QCA6390_PCIE_SCRATCH_0_SOC_PCIE_REG,
plat_priv->qrtr_node_id);
if (ret) {
cnss_pr_err("Failed to write register offset 0x%x, err = %d\n",
QCA6390_PCIE_SCRATCH_0_SOC_PCIE_REG, ret);
goto out;
}
if (cnss_pci_reg_read(pci_priv,
QCA6390_PCIE_SCRATCH_0_SOC_PCIE_REG,
&val))
cnss_pr_err("Failed to read QCA6390_PCIE_SCRATCH_0_SOC_PCIE_REG");
if (val != plat_priv->qrtr_node_id) {
cnss_pr_err("qrtr node id write to register doesn't match with readout value");
goto out;
}
}
ret = cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_POWER_ON);
if (ret)
goto out;
@ -3393,7 +3494,8 @@ static int cnss_pci_probe(struct pci_dev *pci_dev,
{
int ret = 0;
struct cnss_pci_data *pci_priv;
struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(NULL);
int rc_num = pci_dev->bus->domain_nr;
struct cnss_plat_data *plat_priv = cnss_get_plat_priv_by_rc_num(rc_num);
cnss_pr_dbg("PCI is probing, vendor ID: 0x%x, device ID: 0x%x\n",
id->vendor, pci_dev->device);
@ -3458,6 +3560,8 @@ static int cnss_pci_probe(struct pci_dev *pci_dev,
switch (pci_dev->device) {
case QCA6174_DEVICE_ID:
if (cnss_get_dual_wlan() && !plat_priv->enumerate_done)
break;
pci_read_config_word(pci_dev, QCA6174_REV_ID_OFFSET,
&pci_priv->revision_id);
ret = cnss_suspend_pci_link(pci_priv);
@ -3468,7 +3572,9 @@ static int cnss_pci_probe(struct pci_dev *pci_dev,
break;
case QCA6290_DEVICE_ID:
case QCA6390_DEVICE_ID:
cnss_pci_set_wlaon_pwr_ctrl(pci_priv, false, false, false);
if (cnss_get_dual_wlan() && plat_priv->enumerate_done)
cnss_pci_set_wlaon_pwr_ctrl(pci_priv, false,
false, false);
case QCN7605_DEVICE_ID:
setup_timer(&pci_priv->dev_rddm_timer,
cnss_dev_rddm_timeout_hdlr,
@ -3493,6 +3599,9 @@ static int cnss_pci_probe(struct pci_dev *pci_dev,
if (EMULATION_HW)
break;
if (cnss_get_dual_wlan() && !plat_priv->enumerate_done)
break;
if (pci_dev->device != QCN7605_DEVICE_ID)
cnss_pci_set_wlaon_pwr_ctrl(pci_priv, false,
true, false);
@ -3577,7 +3686,7 @@ static const struct dev_pm_ops cnss_pm_ops = {
cnss_pci_runtime_idle)
};
struct pci_driver cnss_pci_driver = {
static struct pci_driver cnss_pci_driver = {
.name = "cnss_pci",
.id_table = cnss_pci_id_table,
.probe = cnss_pci_probe,
@ -3613,19 +3722,79 @@ retry:
}
}
ret = pci_register_driver(&cnss_pci_driver);
if (ret) {
cnss_pr_err("Failed to register to PCI framework, err = %d\n",
ret);
goto out;
}
/* in the dual wlan card case, if call pci_register_driver after
* finishing the first pcie device enumeration, it will cause
* the cnss_pci_probe called in advance with the second wlan card,
* and the sequence like this:
* enter msm_pcie_enumerate -> pci_bus_add_devices -> cnss_pci_probe
* -> exit msm_pcie_enumerate.
* But the correct sequence we expected is like this:
* enter msm_pcie_enumerate -> pci_bus_add_devices ->
* exit msm_pcie_enumerate -> cnss_pci_probe.
* And this unexpected sequence will make the second wlan card do
* pcie link suspend while the pcie enumeration not finished.
* So need to add below logical to avoid doing pcie link suspend
* if the enumeration has not finish.
*/
if (cnss_get_dual_wlan()) {
plat_priv->enumerate_done = true;
/* Now enumeration is finished, try to suspend PCIe link */
if (plat_priv->bus_priv) {
struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
struct pci_dev *pci_dev = pci_priv->pci_dev;
switch (pci_dev->device) {
case QCA6174_DEVICE_ID:
pci_read_config_word(pci_dev,
QCA6174_REV_ID_OFFSET,
&pci_priv->revision_id);
ret = cnss_suspend_pci_link(pci_priv);
if (ret)
cnss_pr_err("Failed to suspend PCI link, err = %d\n",
ret);
cnss_power_off_device(plat_priv);
break;
case QCA6290_DEVICE_ID:
case QCA6390_DEVICE_ID:
case QCN7605_DEVICE_ID:
if (pci_dev->device != QCN7605_DEVICE_ID) {
cnss_pci_set_wlaon_pwr_ctrl(pci_priv,
false,
false,
false);
cnss_pci_set_wlaon_pwr_ctrl(pci_priv,
false,
true,
false);
}
ret = cnss_suspend_pci_link(pci_priv);
if (ret)
cnss_pr_err("Failed to suspend PCI link, err = %d\n",
ret);
cnss_power_off_device(plat_priv);
if (!plat_priv->bus_priv) {
cnss_pr_err("Failed to probe pci driver\n");
ret = -ENODEV;
goto deinit;
break;
default:
cnss_pr_err("Unknown PCI device found: 0x%x\n",
pci_dev->device);
ret = -ENODEV;
}
}
}
if (!cnss_driver_registered) {
ret = pci_register_driver(&cnss_pci_driver);
if (ret) {
cnss_pr_err("Failed to register to PCI framework, err = %d\n",
ret);
goto out;
}
if (!plat_priv->bus_priv) {
cnss_pr_err("Failed to probe pci driver\n");
ret = -ENODEV;
goto deinit;
}
cnss_driver_registered = true;
}
return 0;
deinit:

@ -1726,9 +1726,18 @@ int cnss_qmi_init(struct cnss_plat_data *plat_priv)
cnss_pr_err("Failed to initialize QMI handle, err: %d\n", ret);
goto out;
}
ret = qmi_add_lookup(&plat_priv->qmi_wlfw, WLFW_SERVICE_ID_V01,
WLFW_SERVICE_VERS_V01, WLFW_SERVICE_INS_ID_V01);
/* In order to support dual wlan card attach case,
* need separate qmi service instance id for each dev
*/
if (plat_priv->qrtr_node_id != 0 &&
plat_priv->wlfw_service_instance_id != 0)
ret = qmi_add_lookup(&plat_priv->qmi_wlfw, WLFW_SERVICE_ID_V01,
WLFW_SERVICE_VERS_V01,
plat_priv->wlfw_service_instance_id);
else
ret = qmi_add_lookup(&plat_priv->qmi_wlfw, WLFW_SERVICE_ID_V01,
WLFW_SERVICE_VERS_V01,
WLFW_SERVICE_INS_ID_V01);
if (ret < 0)
cnss_pr_err("Failed to add QMI lookup, err: %d\n", ret);

@ -37,6 +37,7 @@ struct cnss_qmi_event_qdss_trace_save_data {
char file_name[QDSS_TRACE_FILE_NAME_MAX + 1];
};
#define FW_ID_BASE 7
#ifdef CONFIG_CNSS2_QMI
#include "wlan_firmware_service_v01.h"

Loading…
Cancel
Save