mirror of
https://github.com/rd-stuffs/msm-4.14.git
synced 2025-02-20 11:45:48 +08:00
Merge "cnss2: Support dual wlan cards managed by cnss2 platform driver"
This commit is contained in:
commit
a1cfcac78f
@ -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;
|
||||
@ -3264,6 +3327,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;
|
||||
@ -3442,7 +3543,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);
|
||||
@ -3507,6 +3609,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);
|
||||
@ -3517,7 +3621,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,
|
||||
@ -3542,6 +3648,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);
|
||||
@ -3626,7 +3735,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,
|
||||
@ -3662,19 +3771,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;
|
||||
|
||||
if (!plat_priv->bus_priv) {
|
||||
cnss_pr_err("Failed to probe pci driver\n");
|
||||
ret = -ENODEV;
|
||||
goto deinit;
|
||||
}
|
||||
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);
|
||||
|
||||
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…
x
Reference in New Issue
Block a user