summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/net/wireless/cnss2/bus.c192
-rw-r--r--drivers/net/wireless/cnss2/bus.h14
-rw-r--r--drivers/net/wireless/cnss2/main.c567
-rw-r--r--drivers/net/wireless/cnss2/main.h14
-rw-r--r--drivers/net/wireless/cnss2/pci.c551
-rw-r--r--drivers/net/wireless/cnss2/pci.h13
6 files changed, 799 insertions, 552 deletions
diff --git a/drivers/net/wireless/cnss2/bus.c b/drivers/net/wireless/cnss2/bus.c
index 83809c2038c0..0d46b4f6b6a4 100644
--- a/drivers/net/wireless/cnss2/bus.c
+++ b/drivers/net/wireless/cnss2/bus.c
@@ -41,6 +41,38 @@ enum cnss_dev_bus_type cnss_get_bus_type(unsigned long device_id)
}
}
+void *cnss_bus_dev_to_bus_priv(struct device *dev)
+{
+ if (!dev)
+ return NULL;
+
+ switch (cnss_get_dev_bus_type(dev)) {
+ case CNSS_BUS_PCI:
+ return cnss_get_pci_priv(to_pci_dev(dev));
+ default:
+ return NULL;
+ }
+}
+
+struct cnss_plat_data *cnss_bus_dev_to_plat_priv(struct device *dev)
+{
+ void *bus_priv;
+
+ if (!dev)
+ return cnss_get_plat_priv(NULL);
+
+ bus_priv = cnss_bus_dev_to_bus_priv(dev);
+ if (!bus_priv)
+ return NULL;
+
+ switch (cnss_get_dev_bus_type(dev)) {
+ case CNSS_BUS_PCI:
+ return cnss_pci_priv_to_plat_priv(bus_priv);
+ default:
+ return NULL;
+ }
+}
+
int cnss_bus_init(struct cnss_plat_data *plat_priv)
{
if (!plat_priv)
@@ -150,11 +182,19 @@ void cnss_bus_fw_boot_timeout_hdlr(unsigned long data)
void cnss_bus_collect_dump_info(struct cnss_plat_data *plat_priv)
{
+ int ret;
+
if (!plat_priv)
return;
switch (plat_priv->bus_type) {
case CNSS_BUS_PCI:
+ ret = cnss_pci_set_mhi_state(plat_priv->bus_priv,
+ CNSS_MHI_RDDM);
+ if (ret) {
+ cnss_pr_err("Failed to complete RDDM, err = %d\n", ret);
+ break;
+ }
return cnss_pci_collect_dump_info(plat_priv->bus_priv);
default:
cnss_pr_err("Unsupported bus type: %d\n",
@@ -162,3 +202,155 @@ void cnss_bus_collect_dump_info(struct cnss_plat_data *plat_priv)
return;
}
}
+
+int cnss_bus_call_driver_probe(struct cnss_plat_data *plat_priv)
+{
+ if (!plat_priv)
+ return -ENODEV;
+
+ switch (plat_priv->bus_type) {
+ case CNSS_BUS_PCI:
+ return cnss_pci_call_driver_probe(plat_priv->bus_priv);
+ default:
+ cnss_pr_err("Unsupported bus type: %d\n",
+ plat_priv->bus_type);
+ return -EINVAL;
+ }
+}
+
+int cnss_bus_call_driver_remove(struct cnss_plat_data *plat_priv)
+{
+ if (!plat_priv)
+ return -ENODEV;
+
+ switch (plat_priv->bus_type) {
+ case CNSS_BUS_PCI:
+ return cnss_pci_call_driver_remove(plat_priv->bus_priv);
+ default:
+ cnss_pr_err("Unsupported bus type: %d\n",
+ plat_priv->bus_type);
+ return -EINVAL;
+ }
+}
+
+int cnss_bus_dev_powerup(struct cnss_plat_data *plat_priv)
+{
+ if (!plat_priv)
+ return -ENODEV;
+
+ switch (plat_priv->bus_type) {
+ case CNSS_BUS_PCI:
+ return cnss_pci_dev_powerup(plat_priv->bus_priv);
+ default:
+ cnss_pr_err("Unsupported bus type: %d\n",
+ plat_priv->bus_type);
+ return -EINVAL;
+ }
+}
+
+int cnss_bus_dev_shutdown(struct cnss_plat_data *plat_priv)
+{
+ if (!plat_priv)
+ return -ENODEV;
+
+ switch (plat_priv->bus_type) {
+ case CNSS_BUS_PCI:
+ return cnss_pci_dev_shutdown(plat_priv->bus_priv);
+ default:
+ cnss_pr_err("Unsupported bus type: %d\n",
+ plat_priv->bus_type);
+ return -EINVAL;
+ }
+}
+
+int cnss_bus_dev_crash_shutdown(struct cnss_plat_data *plat_priv)
+{
+ if (!plat_priv)
+ return -ENODEV;
+
+ switch (plat_priv->bus_type) {
+ case CNSS_BUS_PCI:
+ return cnss_pci_dev_crash_shutdown(plat_priv->bus_priv);
+ default:
+ cnss_pr_err("Unsupported bus type: %d\n",
+ plat_priv->bus_type);
+ return -EINVAL;
+ }
+}
+
+int cnss_bus_dev_ramdump(struct cnss_plat_data *plat_priv)
+{
+ if (!plat_priv)
+ return -ENODEV;
+
+ switch (plat_priv->bus_type) {
+ case CNSS_BUS_PCI:
+ return cnss_pci_dev_ramdump(plat_priv->bus_priv);
+ default:
+ cnss_pr_err("Unsupported bus type: %d\n",
+ plat_priv->bus_type);
+ return -EINVAL;
+ }
+}
+
+int cnss_bus_register_driver_hdlr(struct cnss_plat_data *plat_priv, void *data)
+{
+ if (!plat_priv)
+ return -ENODEV;
+
+ switch (plat_priv->bus_type) {
+ case CNSS_BUS_PCI:
+ return cnss_pci_register_driver_hdlr(plat_priv->bus_priv, data);
+ default:
+ cnss_pr_err("Unsupported bus type: %d\n",
+ plat_priv->bus_type);
+ return -EINVAL;
+ }
+}
+
+int cnss_bus_unregister_driver_hdlr(struct cnss_plat_data *plat_priv)
+{
+ if (!plat_priv)
+ return -ENODEV;
+
+ switch (plat_priv->bus_type) {
+ case CNSS_BUS_PCI:
+ return cnss_pci_unregister_driver_hdlr(plat_priv->bus_priv);
+ default:
+ cnss_pr_err("Unsupported bus type: %d\n",
+ plat_priv->bus_type);
+ return -EINVAL;
+ }
+}
+
+int cnss_bus_call_driver_modem_status(struct cnss_plat_data *plat_priv,
+ int modem_current_status)
+{
+ if (!plat_priv)
+ return -ENODEV;
+
+ switch (plat_priv->bus_type) {
+ case CNSS_BUS_PCI:
+ return cnss_pci_call_driver_modem_status(plat_priv->bus_priv,
+ modem_current_status);
+ default:
+ cnss_pr_err("Unsupported bus type: %d\n",
+ plat_priv->bus_type);
+ return -EINVAL;
+ }
+}
+
+int cnss_bus_recovery_update_status(struct cnss_plat_data *plat_priv)
+{
+ if (!plat_priv)
+ return -ENODEV;
+
+ switch (plat_priv->bus_type) {
+ case CNSS_BUS_PCI:
+ return cnss_pci_recovery_update_status(plat_priv->bus_priv);
+ default:
+ cnss_pr_err("Unsupported bus type: %d\n",
+ plat_priv->bus_type);
+ return -EINVAL;
+ }
+}
diff --git a/drivers/net/wireless/cnss2/bus.h b/drivers/net/wireless/cnss2/bus.h
index 40400db6e896..4e3d1500bd76 100644
--- a/drivers/net/wireless/cnss2/bus.h
+++ b/drivers/net/wireless/cnss2/bus.h
@@ -27,6 +27,8 @@
enum cnss_dev_bus_type cnss_get_dev_bus_type(struct device *dev);
enum cnss_dev_bus_type cnss_get_bus_type(unsigned long device_id);
+void *cnss_bus_dev_to_bus_priv(struct device *dev);
+struct cnss_plat_data *cnss_bus_dev_to_plat_priv(struct device *dev);
int cnss_bus_init(struct cnss_plat_data *plat_priv);
void cnss_bus_deinit(struct cnss_plat_data *plat_priv);
int cnss_bus_load_m3(struct cnss_plat_data *plat_priv);
@@ -35,5 +37,15 @@ u32 cnss_bus_get_wake_irq(struct cnss_plat_data *plat_priv);
int cnss_bus_force_fw_assert_hdlr(struct cnss_plat_data *plat_priv);
void cnss_bus_fw_boot_timeout_hdlr(unsigned long data);
void cnss_bus_collect_dump_info(struct cnss_plat_data *plat_priv);
-
+int cnss_bus_call_driver_probe(struct cnss_plat_data *plat_priv);
+int cnss_bus_call_driver_remove(struct cnss_plat_data *plat_priv);
+int cnss_bus_dev_powerup(struct cnss_plat_data *plat_priv);
+int cnss_bus_dev_shutdown(struct cnss_plat_data *plat_priv);
+int cnss_bus_dev_crash_shutdown(struct cnss_plat_data *plat_priv);
+int cnss_bus_dev_ramdump(struct cnss_plat_data *plat_priv);
+int cnss_bus_register_driver_hdlr(struct cnss_plat_data *plat_priv, void *data);
+int cnss_bus_unregister_driver_hdlr(struct cnss_plat_data *plat_priv);
+int cnss_bus_call_driver_modem_status(struct cnss_plat_data *plat_priv,
+ int modem_current_status);
+int cnss_bus_recovery_update_status(struct cnss_plat_data *plat_priv);
#endif /* _CNSS_BUS_H */
diff --git a/drivers/net/wireless/cnss2/main.c b/drivers/net/wireless/cnss2/main.c
index 165dd5625a8f..10bcad10bb20 100644
--- a/drivers/net/wireless/cnss2/main.c
+++ b/drivers/net/wireless/cnss2/main.c
@@ -25,7 +25,6 @@
#include "main.h"
#include "bus.h"
#include "debug.h"
-#include "pci.h"
#define CNSS_DUMP_FORMAT_VER 0x11
#define CNSS_DUMP_FORMAT_VER_V2 0x22
@@ -55,13 +54,6 @@ module_param(enable_waltest, bool, 0600);
MODULE_PARM_DESC(enable_waltest, "Enable to handle firmware waltest");
#endif
-enum cnss_debug_quirks {
- LINK_DOWN_SELF_RECOVERY,
- SKIP_DEVICE_BOOT,
- USE_CORE_ONLY_FW,
- SKIP_RECOVERY,
-};
-
unsigned long quirks;
#ifdef CONFIG_CNSS2_DEBUG
module_param(quirks, ulong, 0600);
@@ -93,44 +85,11 @@ static void cnss_set_plat_priv(struct platform_device *plat_dev,
plat_env = plat_priv;
}
-static struct cnss_plat_data *cnss_get_plat_priv(struct platform_device
- *plat_dev)
+struct cnss_plat_data *cnss_get_plat_priv(struct platform_device *plat_dev)
{
return plat_env;
}
-void *cnss_bus_dev_to_bus_priv(struct device *dev)
-{
- if (!dev)
- return NULL;
-
- switch (cnss_get_dev_bus_type(dev)) {
- case CNSS_BUS_PCI:
- return cnss_get_pci_priv(to_pci_dev(dev));
- default:
- return NULL;
- }
-}
-
-struct cnss_plat_data *cnss_bus_dev_to_plat_priv(struct device *dev)
-{
- void *bus_priv;
-
- if (!dev)
- return cnss_get_plat_priv(NULL);
-
- bus_priv = cnss_bus_dev_to_bus_priv(dev);
- if (!bus_priv)
- return NULL;
-
- switch (cnss_get_dev_bus_type(dev)) {
- case CNSS_BUS_PCI:
- return cnss_pci_priv_to_plat_priv(bus_priv);
- default:
- return NULL;
- }
-}
-
static int cnss_pm_notify(struct notifier_block *b,
unsigned long event, void *p)
{
@@ -475,6 +434,16 @@ int cnss_set_fw_log_mode(struct device *dev, u8 fw_log_mode)
}
EXPORT_SYMBOL(cnss_set_fw_log_mode);
+unsigned long *cnss_get_debug_quirks(void)
+{
+ return &quirks;
+}
+
+bool *cnss_get_qmi_bypass(void)
+{
+ return &qmi_bypass;
+}
+
static int cnss_fw_mem_ready_hdlr(struct cnss_plat_data *plat_priv)
{
int ret = 0;
@@ -505,79 +474,6 @@ out:
return ret;
}
-static int cnss_driver_call_probe(struct cnss_plat_data *plat_priv)
-{
- int ret = 0;
- struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
-
- if (test_bit(CNSS_DRIVER_DEBUG, &plat_priv->driver_state)) {
- clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
- cnss_pr_dbg("Skip driver probe\n");
- goto out;
- }
-
- if (!plat_priv->driver_ops) {
- cnss_pr_err("driver_ops is NULL\n");
- ret = -EINVAL;
- goto out;
- }
-
- if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state) &&
- test_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state)) {
- ret = plat_priv->driver_ops->reinit(pci_priv->pci_dev,
- pci_priv->pci_device_id);
- if (ret) {
- cnss_pr_err("Failed to reinit host driver, err = %d\n",
- ret);
- goto out;
- }
- clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
- } else if (test_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state)) {
- ret = plat_priv->driver_ops->probe(pci_priv->pci_dev,
- pci_priv->pci_device_id);
- if (ret) {
- cnss_pr_err("Failed to probe host driver, err = %d\n",
- ret);
- goto out;
- }
- clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
- clear_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state);
- set_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state);
- }
-
- return 0;
-
-out:
- return ret;
-}
-
-static int cnss_driver_call_remove(struct cnss_plat_data *plat_priv)
-{
- struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
-
- if (test_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state) ||
- test_bit(CNSS_FW_BOOT_RECOVERY, &plat_priv->driver_state) ||
- test_bit(CNSS_DRIVER_DEBUG, &plat_priv->driver_state)) {
- cnss_pr_dbg("Skip driver remove\n");
- return 0;
- }
-
- if (!plat_priv->driver_ops) {
- cnss_pr_err("driver_ops is NULL\n");
- return -EINVAL;
- }
-
- if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state) &&
- test_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state)) {
- plat_priv->driver_ops->shutdown(pci_priv->pci_dev);
- } else if (test_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state)) {
- plat_priv->driver_ops->remove(pci_priv->pci_dev);
- clear_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state);
- }
-
- return 0;
-}
-
static int cnss_fw_ready_hdlr(struct cnss_plat_data *plat_priv)
{
int ret = 0;
@@ -601,7 +497,7 @@ static int cnss_fw_ready_hdlr(struct cnss_plat_data *plat_priv)
QMI_WLFW_CALIBRATION_V01);
} else if (test_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state) ||
test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) {
- ret = cnss_driver_call_probe(plat_priv);
+ ret = cnss_bus_call_driver_probe(plat_priv);
} else {
complete(&plat_priv->power_up_complete);
}
@@ -614,9 +510,7 @@ static int cnss_fw_ready_hdlr(struct cnss_plat_data *plat_priv)
return 0;
shutdown:
- cnss_pci_stop_mhi(plat_priv->bus_priv);
- cnss_suspend_pci_link(plat_priv->bus_priv);
- cnss_power_off_device(plat_priv);
+ cnss_bus_dev_shutdown(plat_priv);
clear_bit(CNSS_FW_READY, &plat_priv->driver_state);
clear_bit(CNSS_FW_MEM_READY, &plat_priv->driver_state);
@@ -788,44 +682,6 @@ int cnss_power_down(struct device *dev)
}
EXPORT_SYMBOL(cnss_power_down);
-int cnss_wlan_register_driver(struct cnss_wlan_driver *driver_ops)
-{
- int ret = 0;
- struct cnss_plat_data *plat_priv = cnss_get_plat_priv(NULL);
-
- if (!plat_priv) {
- cnss_pr_err("plat_priv is NULL!\n");
- return -ENODEV;
- }
-
- if (plat_priv->driver_ops) {
- cnss_pr_err("Driver has already registered!\n");
- return -EEXIST;
- }
-
- ret = cnss_driver_event_post(plat_priv,
- CNSS_DRIVER_EVENT_REGISTER_DRIVER,
- CNSS_EVENT_SYNC_UNINTERRUPTIBLE,
- driver_ops);
- return ret;
-}
-EXPORT_SYMBOL(cnss_wlan_register_driver);
-
-void cnss_wlan_unregister_driver(struct cnss_wlan_driver *driver_ops)
-{
- struct cnss_plat_data *plat_priv = cnss_get_plat_priv(NULL);
-
- if (!plat_priv) {
- cnss_pr_err("plat_priv is NULL!\n");
- return;
- }
-
- cnss_driver_event_post(plat_priv,
- CNSS_DRIVER_EVENT_UNREGISTER_DRIVER,
- CNSS_EVENT_SYNC_UNINTERRUPTIBLE, NULL);
-}
-EXPORT_SYMBOL(cnss_wlan_unregister_driver);
-
static int cnss_get_resources(struct cnss_plat_data *plat_priv)
{
int ret = 0;
@@ -857,13 +713,11 @@ static int cnss_modem_notifier_nb(struct notifier_block *nb,
{
struct cnss_plat_data *plat_priv =
container_of(nb, struct cnss_plat_data, modem_nb);
- struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
struct cnss_esoc_info *esoc_info;
- struct cnss_wlan_driver *driver_ops;
cnss_pr_dbg("Modem notifier: event %lu\n", code);
- if (!pci_priv)
+ if (!plat_priv)
return NOTIFY_DONE;
esoc_info = &plat_priv->esoc_info;
@@ -875,13 +729,10 @@ static int cnss_modem_notifier_nb(struct notifier_block *nb,
else
return NOTIFY_DONE;
- driver_ops = plat_priv->driver_ops;
- if (!driver_ops || !driver_ops->modem_status)
+ if (!cnss_bus_call_driver_modem_status(plat_priv,
+ esoc_info->modem_current_status))
return NOTIFY_DONE;
- driver_ops->modem_status(pci_priv->pci_dev,
- esoc_info->modem_current_status);
-
return NOTIFY_OK;
}
@@ -955,246 +806,6 @@ static void cnss_unregister_esoc(struct cnss_plat_data *plat_priv)
devm_unregister_esoc_client(dev, esoc_info->esoc_desc);
}
-static int cnss_qca6174_powerup(struct cnss_plat_data *plat_priv)
-{
- int ret = 0;
- struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
-
- if (!pci_priv) {
- cnss_pr_err("pci_priv is NULL!\n");
- return -ENODEV;
- }
-
- ret = cnss_power_on_device(plat_priv);
- if (ret) {
- cnss_pr_err("Failed to power on device, err = %d\n", ret);
- goto out;
- }
-
- ret = cnss_resume_pci_link(pci_priv);
- if (ret) {
- cnss_pr_err("Failed to resume PCI link, err = %d\n", ret);
- goto power_off;
- }
-
- ret = cnss_driver_call_probe(plat_priv);
- if (ret)
- goto suspend_link;
-
- return 0;
-suspend_link:
- cnss_suspend_pci_link(pci_priv);
-power_off:
- cnss_power_off_device(plat_priv);
-out:
- return ret;
-}
-
-static int cnss_qca6174_shutdown(struct cnss_plat_data *plat_priv)
-{
- int ret = 0;
- struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
-
- if (!pci_priv)
- return -ENODEV;
-
- cnss_pm_request_resume(pci_priv);
-
- cnss_driver_call_remove(plat_priv);
-
- cnss_request_bus_bandwidth(&plat_priv->plat_dev->dev,
- CNSS_BUS_WIDTH_NONE);
- cnss_pci_set_monitor_wake_intr(pci_priv, false);
- cnss_pci_set_auto_suspended(pci_priv, 0);
-
- 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);
-
- clear_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state);
-
- return ret;
-}
-
-static void cnss_qca6174_crash_shutdown(struct cnss_plat_data *plat_priv)
-{
- struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
-
- if (!plat_priv->driver_ops)
- return;
-
- plat_priv->driver_ops->crash_shutdown(pci_priv->pci_dev);
-}
-
-static int cnss_qca6290_powerup(struct cnss_plat_data *plat_priv)
-{
- int ret = 0;
- struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
- unsigned int timeout;
-
- if (!pci_priv) {
- cnss_pr_err("pci_priv is NULL!\n");
- return -ENODEV;
- }
-
- if (plat_priv->ramdump_info_v2.dump_data_valid ||
- test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) {
- cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_DEINIT);
- cnss_pci_clear_dump_info(pci_priv);
- }
-
- ret = cnss_power_on_device(plat_priv);
- if (ret) {
- cnss_pr_err("Failed to power on device, err = %d\n", ret);
- goto out;
- }
-
- ret = cnss_resume_pci_link(pci_priv);
- if (ret) {
- cnss_pr_err("Failed to resume PCI link, err = %d\n", ret);
- goto power_off;
- }
-
- timeout = cnss_get_qmi_timeout();
-
- ret = cnss_pci_start_mhi(pci_priv);
- if (ret) {
- cnss_pr_err("Failed to start MHI, err = %d\n", ret);
- if (!test_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state) &&
- !pci_priv->pci_link_down_ind && timeout)
- mod_timer(&plat_priv->fw_boot_timer,
- jiffies + msecs_to_jiffies(timeout >> 1));
- return 0;
- }
-
- if (test_bit(USE_CORE_ONLY_FW, &quirks)) {
- clear_bit(CNSS_FW_BOOT_RECOVERY, &plat_priv->driver_state);
- clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
- return 0;
- }
-
- cnss_set_pin_connect_status(plat_priv);
-
- if (qmi_bypass) {
- ret = cnss_driver_call_probe(plat_priv);
- if (ret)
- goto stop_mhi;
- } else if (timeout) {
- mod_timer(&plat_priv->fw_boot_timer,
- jiffies + msecs_to_jiffies(timeout << 1));
- }
-
- return 0;
-
-stop_mhi:
- cnss_pci_stop_mhi(pci_priv);
- cnss_suspend_pci_link(pci_priv);
-power_off:
- cnss_power_off_device(plat_priv);
-out:
- return ret;
-}
-
-static int cnss_qca6290_shutdown(struct cnss_plat_data *plat_priv)
-{
- int ret = 0;
- struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
-
- if (!pci_priv)
- return -ENODEV;
-
- cnss_pm_request_resume(pci_priv);
-
- cnss_driver_call_remove(plat_priv);
-
- cnss_request_bus_bandwidth(&plat_priv->plat_dev->dev,
- CNSS_BUS_WIDTH_NONE);
- cnss_pci_set_monitor_wake_intr(pci_priv, false);
- cnss_pci_set_auto_suspended(pci_priv, 0);
-
- cnss_pci_stop_mhi(pci_priv);
-
- 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);
-
- clear_bit(CNSS_FW_READY, &plat_priv->driver_state);
- clear_bit(CNSS_FW_MEM_READY, &plat_priv->driver_state);
- clear_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state);
-
- return ret;
-}
-
-static void cnss_qca6290_crash_shutdown(struct cnss_plat_data *plat_priv)
-{
- struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
- int ret = 0;
-
- cnss_pr_dbg("Crash shutdown with driver_state 0x%lx\n",
- plat_priv->driver_state);
-
- if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state) ||
- test_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state) ||
- test_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state)) {
- cnss_pr_dbg("Ignore crash shutdown\n");
- return;
- }
-
- ret = cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_RDDM_KERNEL_PANIC);
- if (ret) {
- cnss_pr_err("Fail to complete RDDM, err = %d\n", ret);
- return;
- }
-
- cnss_pci_collect_dump_info(pci_priv);
-}
-
-static int cnss_powerup(struct cnss_plat_data *plat_priv)
-{
- int ret;
-
- switch (plat_priv->device_id) {
- case QCA6174_DEVICE_ID:
- ret = cnss_qca6174_powerup(plat_priv);
- break;
- case QCA6290_EMULATION_DEVICE_ID:
- case QCA6290_DEVICE_ID:
- ret = cnss_qca6290_powerup(plat_priv);
- break;
- default:
- cnss_pr_err("Unknown device_id found: 0x%lx\n",
- plat_priv->device_id);
- ret = -ENODEV;
- }
-
- return ret;
-}
-
-static int cnss_shutdown(struct cnss_plat_data *plat_priv)
-{
- int ret;
-
- switch (plat_priv->device_id) {
- case QCA6174_DEVICE_ID:
- ret = cnss_qca6174_shutdown(plat_priv);
- break;
- case QCA6290_EMULATION_DEVICE_ID:
- case QCA6290_DEVICE_ID:
- ret = cnss_qca6290_shutdown(plat_priv);
- break;
- default:
- cnss_pr_err("Unknown device_id found: 0x%lx\n",
- plat_priv->device_id);
- ret = -ENODEV;
- }
-
- return ret;
-}
-
static int cnss_subsys_powerup(const struct subsys_desc *subsys_desc)
{
struct cnss_plat_data *plat_priv;
@@ -1215,7 +826,7 @@ static int cnss_subsys_powerup(const struct subsys_desc *subsys_desc)
return 0;
}
- return cnss_powerup(plat_priv);
+ return cnss_bus_dev_powerup(plat_priv);
}
static int cnss_subsys_shutdown(const struct subsys_desc *subsys_desc,
@@ -1239,68 +850,12 @@ static int cnss_subsys_shutdown(const struct subsys_desc *subsys_desc,
return 0;
}
- return cnss_shutdown(plat_priv);
-}
-
-static int cnss_qca6290_ramdump(struct cnss_plat_data *plat_priv)
-{
- struct cnss_ramdump_info_v2 *info_v2 = &plat_priv->ramdump_info_v2;
- struct cnss_dump_data *dump_data = &info_v2->dump_data;
- struct cnss_dump_seg *dump_seg = info_v2->dump_data_vaddr;
- struct ramdump_segment *ramdump_segs, *s;
- int i, ret = 0;
-
- if (!info_v2->dump_data_valid ||
- dump_data->nentries == 0)
- return 0;
-
- ramdump_segs = kcalloc(dump_data->nentries,
- sizeof(*ramdump_segs),
- GFP_KERNEL);
- if (!ramdump_segs)
- return -ENOMEM;
-
- s = ramdump_segs;
- for (i = 0; i < dump_data->nentries; i++) {
- s->address = dump_seg->address;
- s->v_address = dump_seg->v_address;
- s->size = dump_seg->size;
- s++;
- dump_seg++;
- }
-
- ret = do_elf_ramdump(info_v2->ramdump_dev, ramdump_segs,
- dump_data->nentries);
- kfree(ramdump_segs);
-
- cnss_pci_set_mhi_state(plat_priv->bus_priv, CNSS_MHI_DEINIT);
- cnss_pci_clear_dump_info(plat_priv->bus_priv);
-
- return ret;
-}
-
-static int cnss_qca6174_ramdump(struct cnss_plat_data *plat_priv)
-{
- int ret = 0;
- struct cnss_ramdump_info *ramdump_info;
- struct ramdump_segment segment;
-
- ramdump_info = &plat_priv->ramdump_info;
- if (!ramdump_info->ramdump_size)
- return -EINVAL;
-
- memset(&segment, 0, sizeof(segment));
- segment.v_address = ramdump_info->ramdump_va;
- segment.size = ramdump_info->ramdump_size;
- ret = do_ramdump(ramdump_info->ramdump_dev, &segment, 1);
-
- return ret;
+ return cnss_bus_dev_shutdown(plat_priv);
}
static int cnss_subsys_ramdump(int enable,
const struct subsys_desc *subsys_desc)
{
- int ret = 0;
struct cnss_plat_data *plat_priv = dev_get_drvdata(subsys_desc->dev);
if (!plat_priv) {
@@ -1311,21 +866,7 @@ static int cnss_subsys_ramdump(int enable,
if (!enable)
return 0;
- switch (plat_priv->device_id) {
- case QCA6174_DEVICE_ID:
- ret = cnss_qca6174_ramdump(plat_priv);
- break;
- case QCA6290_EMULATION_DEVICE_ID:
- case QCA6290_DEVICE_ID:
- ret = cnss_qca6290_ramdump(plat_priv);
- break;
- default:
- cnss_pr_err("Unknown device_id found: 0x%lx\n",
- plat_priv->device_id);
- ret = -ENODEV;
- }
-
- return ret;
+ return cnss_bus_dev_ramdump(plat_priv);
}
void *cnss_get_virt_ramdump_mem(struct device *dev, unsigned long *size)
@@ -1368,19 +909,7 @@ static void cnss_subsys_crash_shutdown(const struct subsys_desc *subsys_desc)
cnss_pr_err("plat_priv is NULL!\n");
return;
}
-
- switch (plat_priv->device_id) {
- case QCA6174_DEVICE_ID:
- cnss_qca6174_crash_shutdown(plat_priv);
- break;
- case QCA6290_EMULATION_DEVICE_ID:
- case QCA6290_DEVICE_ID:
- cnss_qca6290_crash_shutdown(plat_priv);
- break;
- default:
- cnss_pr_err("Unknown device_id found: 0x%lx\n",
- plat_priv->device_id);
- }
+ cnss_bus_dev_crash_shutdown(plat_priv);
}
static const char *cnss_recovery_reason_to_str(enum cnss_recovery_reason reason)
@@ -1402,20 +931,15 @@ static const char *cnss_recovery_reason_to_str(enum cnss_recovery_reason reason)
static int cnss_do_recovery(struct cnss_plat_data *plat_priv,
enum cnss_recovery_reason reason)
{
- struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
struct cnss_subsys_info *subsys_info =
&plat_priv->subsys_info;
- int ret = 0;
plat_priv->recovery_count++;
if (plat_priv->device_id == QCA6174_DEVICE_ID)
goto self_recovery;
- if (plat_priv->driver_ops &&
- test_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state))
- plat_priv->driver_ops->update_status(pci_priv->pci_dev,
- CNSS_RECOVERY);
+ cnss_bus_recovery_update_status(plat_priv);
if (test_bit(SKIP_RECOVERY, &quirks)) {
cnss_pr_dbg("Skip device recovery\n");
@@ -1429,11 +953,6 @@ static int cnss_do_recovery(struct cnss_plat_data *plat_priv,
break;
case CNSS_REASON_RDDM:
clear_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state);
- ret = cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_RDDM);
- if (ret) {
- cnss_pr_err("Failed to complete RDDM, err = %d\n", ret);
- break;
- }
cnss_bus_collect_dump_info(plat_priv);
break;
case CNSS_REASON_DEFAULT:
@@ -1454,8 +973,8 @@ static int cnss_do_recovery(struct cnss_plat_data *plat_priv,
return 0;
self_recovery:
- cnss_shutdown(plat_priv);
- cnss_powerup(plat_priv);
+ cnss_bus_dev_shutdown(plat_priv);
+ cnss_bus_dev_powerup(plat_priv);
return 0;
}
@@ -1568,38 +1087,12 @@ int cnss_force_fw_assert(struct device *dev)
}
EXPORT_SYMBOL(cnss_force_fw_assert);
-static int cnss_register_driver_hdlr(struct cnss_plat_data *plat_priv,
- void *data)
-{
- int ret = 0;
-
- set_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state);
- plat_priv->driver_ops = data;
-
- ret = cnss_powerup(plat_priv);
- if (ret) {
- clear_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state);
- plat_priv->driver_ops = NULL;
- }
-
- return ret;
-}
-
-static int cnss_unregister_driver_hdlr(struct cnss_plat_data *plat_priv)
-{
- set_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state);
- cnss_shutdown(plat_priv);
- plat_priv->driver_ops = NULL;
-
- return 0;
-}
-
static int cnss_cold_boot_cal_start_hdlr(struct cnss_plat_data *plat_priv)
{
int ret = 0;
set_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state);
- ret = cnss_powerup(plat_priv);
+ ret = cnss_bus_dev_powerup(plat_priv);
if (ret)
clear_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state);
@@ -1610,7 +1103,7 @@ static int cnss_cold_boot_cal_done_hdlr(struct cnss_plat_data *plat_priv)
{
plat_priv->cal_done = true;
cnss_wlfw_wlan_mode_send_sync(plat_priv, QMI_WLFW_OFF_V01);
- cnss_shutdown(plat_priv);
+ cnss_bus_dev_shutdown(plat_priv);
clear_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state);
return 0;
@@ -1618,12 +1111,12 @@ static int cnss_cold_boot_cal_done_hdlr(struct cnss_plat_data *plat_priv)
static int cnss_power_up_hdlr(struct cnss_plat_data *plat_priv)
{
- return cnss_powerup(plat_priv);
+ return cnss_bus_dev_powerup(plat_priv);
}
static int cnss_power_down_hdlr(struct cnss_plat_data *plat_priv)
{
- cnss_shutdown(plat_priv);
+ cnss_bus_dev_shutdown(plat_priv);
return 0;
}
@@ -1682,11 +1175,11 @@ static void cnss_driver_event_work(struct work_struct *work)
ret = cnss_cold_boot_cal_done_hdlr(plat_priv);
break;
case CNSS_DRIVER_EVENT_REGISTER_DRIVER:
- ret = cnss_register_driver_hdlr(plat_priv,
- event->data);
+ ret = cnss_bus_register_driver_hdlr(plat_priv,
+ event->data);
break;
case CNSS_DRIVER_EVENT_UNREGISTER_DRIVER:
- ret = cnss_unregister_driver_hdlr(plat_priv);
+ ret = cnss_bus_unregister_driver_hdlr(plat_priv);
break;
case CNSS_DRIVER_EVENT_RECOVERY:
ret = cnss_driver_recovery_hdlr(plat_priv,
diff --git a/drivers/net/wireless/cnss2/main.h b/drivers/net/wireless/cnss2/main.h
index 7efbb27aee7c..9dc64e016d82 100644
--- a/drivers/net/wireless/cnss2/main.h
+++ b/drivers/net/wireless/cnss2/main.h
@@ -164,6 +164,13 @@ struct cnss_pin_connect_result {
u32 host_pin_result;
};
+enum cnss_debug_quirks {
+ LINK_DOWN_SELF_RECOVERY,
+ SKIP_DEVICE_BOOT,
+ USE_CORE_ONLY_FW,
+ SKIP_RECOVERY,
+};
+
struct cnss_plat_data {
struct platform_device *plat_dev;
void *bus_priv;
@@ -179,7 +186,6 @@ struct cnss_plat_data {
struct cnss_platform_cap cap;
struct pm_qos_request qos_request;
unsigned long device_id;
- struct cnss_wlan_driver *driver_ops;
enum cnss_driver_status driver_status;
u32 recovery_count;
unsigned long driver_state;
@@ -210,8 +216,8 @@ struct cnss_plat_data {
bool cal_done;
};
-void *cnss_bus_dev_to_bus_priv(struct device *dev);
-struct cnss_plat_data *cnss_bus_dev_to_plat_priv(struct device *dev);
+struct cnss_plat_data *cnss_get_plat_priv(struct platform_device *plat_dev);
+unsigned long *cnss_get_debug_quirks(void);
int cnss_driver_event_post(struct cnss_plat_data *plat_priv,
enum cnss_driver_event_type type,
u32 flags, void *data);
@@ -238,5 +244,5 @@ int cnss_register_ramdump(struct cnss_plat_data *plat_priv);
void cnss_unregister_ramdump(struct cnss_plat_data *plat_priv);
void cnss_set_pin_connect_status(struct cnss_plat_data *plat_priv);
u32 cnss_get_wake_msi(struct cnss_plat_data *plat_priv);
-
+bool *cnss_get_qmi_bypass(void);
#endif /* _CNSS_MAIN_H */
diff --git a/drivers/net/wireless/cnss2/pci.c b/drivers/net/wireless/cnss2/pci.c
index 3f2aef84662c..ff053b098c22 100644
--- a/drivers/net/wireless/cnss2/pci.c
+++ b/drivers/net/wireless/cnss2/pci.c
@@ -17,6 +17,7 @@
#include <linux/of.h>
#include <linux/pm_runtime.h>
#include <linux/memblock.h>
+#include <soc/qcom/ramdump.h>
#include "main.h"
#include "bus.h"
@@ -234,6 +235,532 @@ static int cnss_set_pci_link(struct cnss_pci_data *pci_priv, bool link_up)
}
#endif /* CONFIG_PCI_MSM */
+int cnss_pci_recovery_update_status(struct cnss_pci_data *pci_priv)
+{
+ struct cnss_plat_data *plat_priv;
+
+ plat_priv = pci_priv->plat_priv;
+
+ if (pci_priv->driver_ops &&
+ test_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state))
+ pci_priv->driver_ops->update_status(pci_priv->pci_dev,
+ CNSS_RECOVERY);
+ return 0;
+}
+
+int cnss_pci_call_driver_probe(struct cnss_pci_data *pci_priv)
+{
+ int ret = 0;
+ struct cnss_plat_data *plat_priv;
+
+ if (!pci_priv)
+ return -ENODEV;
+
+ plat_priv = pci_priv->plat_priv;
+
+ if (test_bit(CNSS_DRIVER_DEBUG, &plat_priv->driver_state)) {
+ clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
+ cnss_pr_dbg("Skip driver probe\n");
+ goto out;
+ }
+
+ if (!pci_priv->driver_ops) {
+ cnss_pr_err("driver_ops is NULL\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state) &&
+ test_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state)) {
+ ret = pci_priv->driver_ops->reinit(pci_priv->pci_dev,
+ pci_priv->pci_device_id);
+ if (ret) {
+ cnss_pr_err("Failed to reinit host driver, err = %d\n",
+ ret);
+ goto out;
+ }
+ clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
+ } else if (test_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state)) {
+ ret = pci_priv->driver_ops->probe(pci_priv->pci_dev,
+ pci_priv->pci_device_id);
+ if (ret) {
+ cnss_pr_err("Failed to probe host driver, err = %d\n",
+ ret);
+ goto out;
+ }
+ clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
+ clear_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state);
+ set_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state);
+ }
+
+ return 0;
+
+out:
+ return ret;
+}
+
+int cnss_pci_call_driver_remove(struct cnss_pci_data *pci_priv)
+{
+ struct cnss_plat_data *plat_priv;
+
+ if (!pci_priv)
+ return -ENODEV;
+
+ plat_priv = pci_priv->plat_priv;
+
+ if (test_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state) ||
+ test_bit(CNSS_FW_BOOT_RECOVERY, &plat_priv->driver_state) ||
+ test_bit(CNSS_DRIVER_DEBUG, &plat_priv->driver_state)) {
+ cnss_pr_dbg("Skip driver remove\n");
+ return 0;
+ }
+
+ if (!pci_priv->driver_ops) {
+ cnss_pr_err("driver_ops is NULL\n");
+ return -EINVAL;
+ }
+
+ if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state) &&
+ test_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state)) {
+ pci_priv->driver_ops->shutdown(pci_priv->pci_dev);
+ } else if (test_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state)) {
+ pci_priv->driver_ops->remove(pci_priv->pci_dev);
+ clear_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state);
+ }
+
+ return 0;
+}
+
+int cnss_pci_call_driver_modem_status(struct cnss_pci_data *pci_priv,
+ int modem_current_status)
+{
+ struct cnss_wlan_driver *driver_ops;
+
+ if (!pci_priv)
+ return -ENODEV;
+
+ driver_ops = pci_priv->driver_ops;
+ if (!driver_ops || !driver_ops->modem_status)
+ return -EINVAL;
+
+ driver_ops->modem_status(pci_priv->pci_dev, modem_current_status);
+
+ return 0;
+}
+
+static int cnss_qca6174_powerup(struct cnss_pci_data *pci_priv)
+{
+ int ret = 0;
+ struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+
+ ret = cnss_power_on_device(plat_priv);
+ if (ret) {
+ cnss_pr_err("Failed to power on device, err = %d\n", ret);
+ goto out;
+ }
+
+ ret = cnss_resume_pci_link(pci_priv);
+ if (ret) {
+ cnss_pr_err("Failed to resume PCI link, err = %d\n", ret);
+ goto power_off;
+ }
+
+ ret = cnss_pci_call_driver_probe(pci_priv);
+ if (ret)
+ goto suspend_link;
+
+ return 0;
+suspend_link:
+ cnss_suspend_pci_link(pci_priv);
+power_off:
+ cnss_power_off_device(plat_priv);
+out:
+ return ret;
+}
+
+static int cnss_qca6174_shutdown(struct cnss_pci_data *pci_priv)
+{
+ int ret = 0;
+ struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+
+ cnss_pm_request_resume(pci_priv);
+
+ cnss_pci_call_driver_remove(pci_priv);
+
+ cnss_request_bus_bandwidth(&plat_priv->plat_dev->dev,
+ CNSS_BUS_WIDTH_NONE);
+ cnss_pci_set_monitor_wake_intr(pci_priv, false);
+ cnss_pci_set_auto_suspended(pci_priv, 0);
+
+ 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);
+
+ clear_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state);
+
+ return ret;
+}
+
+static void cnss_qca6174_crash_shutdown(struct cnss_pci_data *pci_priv)
+{
+ if (pci_priv->driver_ops && pci_priv->driver_ops->crash_shutdown)
+ pci_priv->driver_ops->crash_shutdown(pci_priv->pci_dev);
+}
+
+static int cnss_qca6174_ramdump(struct cnss_pci_data *pci_priv)
+{
+ int ret = 0;
+ struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+ struct cnss_ramdump_info *ramdump_info;
+ struct ramdump_segment segment;
+
+ ramdump_info = &plat_priv->ramdump_info;
+ if (!ramdump_info->ramdump_size)
+ return -EINVAL;
+
+ memset(&segment, 0, sizeof(segment));
+ segment.v_address = ramdump_info->ramdump_va;
+ segment.size = ramdump_info->ramdump_size;
+ ret = do_ramdump(ramdump_info->ramdump_dev, &segment, 1);
+
+ return ret;
+}
+
+static int cnss_qca6290_powerup(struct cnss_pci_data *pci_priv)
+{
+ int ret = 0;
+ struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+ unsigned int timeout;
+
+ if (plat_priv->ramdump_info_v2.dump_data_valid ||
+ test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) {
+ cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_DEINIT);
+ cnss_pci_clear_dump_info(pci_priv);
+ }
+
+ ret = cnss_power_on_device(plat_priv);
+ if (ret) {
+ cnss_pr_err("Failed to power on device, err = %d\n", ret);
+ goto out;
+ }
+
+ ret = cnss_resume_pci_link(pci_priv);
+ if (ret) {
+ cnss_pr_err("Failed to resume PCI link, err = %d\n", ret);
+ goto power_off;
+ }
+
+ timeout = cnss_get_qmi_timeout();
+
+ ret = cnss_pci_start_mhi(pci_priv);
+ if (ret) {
+ cnss_pr_err("Failed to start MHI, err = %d\n", ret);
+ if (!test_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state) &&
+ !pci_priv->pci_link_down_ind && timeout)
+ mod_timer(&plat_priv->fw_boot_timer,
+ jiffies + msecs_to_jiffies(timeout >> 1));
+ return 0;
+ }
+
+ if (test_bit(USE_CORE_ONLY_FW, cnss_get_debug_quirks())) {
+ clear_bit(CNSS_FW_BOOT_RECOVERY, &plat_priv->driver_state);
+ clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
+ return 0;
+ }
+
+ cnss_set_pin_connect_status(plat_priv);
+
+ if (*cnss_get_qmi_bypass()) {
+ ret = cnss_pci_call_driver_probe(pci_priv);
+ if (ret)
+ goto stop_mhi;
+ } else if (timeout) {
+ mod_timer(&plat_priv->fw_boot_timer,
+ jiffies + msecs_to_jiffies(timeout << 1));
+ }
+
+ return 0;
+
+stop_mhi:
+ cnss_pci_stop_mhi(pci_priv);
+ cnss_suspend_pci_link(pci_priv);
+power_off:
+ cnss_power_off_device(plat_priv);
+out:
+ return ret;
+}
+
+static int cnss_qca6290_shutdown(struct cnss_pci_data *pci_priv)
+{
+ int ret = 0;
+ struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+
+ cnss_pm_request_resume(pci_priv);
+
+ cnss_pci_call_driver_remove(pci_priv);
+
+ cnss_request_bus_bandwidth(&plat_priv->plat_dev->dev,
+ CNSS_BUS_WIDTH_NONE);
+ cnss_pci_set_monitor_wake_intr(pci_priv, false);
+ cnss_pci_set_auto_suspended(pci_priv, 0);
+
+ cnss_pci_stop_mhi(pci_priv);
+
+ 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);
+
+ clear_bit(CNSS_FW_READY, &plat_priv->driver_state);
+ clear_bit(CNSS_FW_MEM_READY, &plat_priv->driver_state);
+ clear_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state);
+
+ return ret;
+}
+
+static void cnss_qca6290_crash_shutdown(struct cnss_pci_data *pci_priv)
+{
+ struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+ int ret = 0;
+
+ cnss_pr_dbg("Crash shutdown with driver_state 0x%lx\n",
+ plat_priv->driver_state);
+
+ if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state) ||
+ test_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state) ||
+ test_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state)) {
+ cnss_pr_dbg("Ignore crash shutdown\n");
+ return;
+ }
+
+ ret = cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_RDDM_KERNEL_PANIC);
+ if (ret) {
+ cnss_pr_err("Fail to complete RDDM, err = %d\n", ret);
+ return;
+ }
+
+ cnss_pci_collect_dump_info(pci_priv);
+}
+
+static int cnss_qca6290_ramdump(struct cnss_pci_data *pci_priv)
+{
+ struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+ struct cnss_ramdump_info_v2 *info_v2 = &plat_priv->ramdump_info_v2;
+ struct cnss_dump_data *dump_data = &info_v2->dump_data;
+ struct cnss_dump_seg *dump_seg = info_v2->dump_data_vaddr;
+ struct ramdump_segment *ramdump_segs, *s;
+ int i, ret = 0;
+
+ if (!info_v2->dump_data_valid ||
+ dump_data->nentries == 0)
+ return 0;
+
+ ramdump_segs = kcalloc(dump_data->nentries,
+ sizeof(*ramdump_segs),
+ GFP_KERNEL);
+ if (!ramdump_segs)
+ return -ENOMEM;
+
+ s = ramdump_segs;
+ for (i = 0; i < dump_data->nentries; i++) {
+ s->address = dump_seg->address;
+ s->v_address = dump_seg->v_address;
+ s->size = dump_seg->size;
+ s++;
+ dump_seg++;
+ }
+
+ ret = do_elf_ramdump(info_v2->ramdump_dev, ramdump_segs,
+ dump_data->nentries);
+ kfree(ramdump_segs);
+
+ cnss_pci_set_mhi_state(plat_priv->bus_priv, CNSS_MHI_DEINIT);
+ cnss_pci_clear_dump_info(plat_priv->bus_priv);
+
+ return ret;
+}
+
+int cnss_pci_dev_powerup(struct cnss_pci_data *pci_priv)
+{
+ int ret = 0;
+
+ if (!pci_priv) {
+ cnss_pr_err("pci_priv is NULL\n");
+ return -ENODEV;
+ }
+
+ switch (pci_priv->device_id) {
+ case QCA6174_DEVICE_ID:
+ ret = cnss_qca6174_powerup(pci_priv);
+ break;
+ case QCA6290_EMULATION_DEVICE_ID:
+ case QCA6290_DEVICE_ID:
+ ret = cnss_qca6290_powerup(pci_priv);
+ break;
+ default:
+ cnss_pr_err("Unknown device_id found: 0x%x\n",
+ pci_priv->device_id);
+ ret = -ENODEV;
+ }
+
+ return ret;
+}
+
+int cnss_pci_dev_shutdown(struct cnss_pci_data *pci_priv)
+{
+ int ret = 0;
+
+ if (!pci_priv) {
+ cnss_pr_err("pci_priv is NULL\n");
+ return -ENODEV;
+ }
+
+ switch (pci_priv->device_id) {
+ case QCA6174_DEVICE_ID:
+ ret = cnss_qca6174_shutdown(pci_priv);
+ break;
+ case QCA6290_EMULATION_DEVICE_ID:
+ case QCA6290_DEVICE_ID:
+ ret = cnss_qca6290_shutdown(pci_priv);
+ break;
+ default:
+ cnss_pr_err("Unknown device_id found: 0x%x\n",
+ pci_priv->device_id);
+ ret = -ENODEV;
+ }
+
+ return ret;
+}
+
+int cnss_pci_dev_crash_shutdown(struct cnss_pci_data *pci_priv)
+{
+ int ret = 0;
+
+ if (!pci_priv) {
+ cnss_pr_err("pci_priv is NULL\n");
+ return -ENODEV;
+ }
+
+ switch (pci_priv->device_id) {
+ case QCA6174_DEVICE_ID:
+ cnss_qca6174_crash_shutdown(pci_priv);
+ break;
+ case QCA6290_EMULATION_DEVICE_ID:
+ case QCA6290_DEVICE_ID:
+ cnss_qca6290_crash_shutdown(pci_priv);
+ break;
+ default:
+ cnss_pr_err("Unknown device_id found: 0x%x\n",
+ pci_priv->device_id);
+ ret = -ENODEV;
+ }
+
+ return ret;
+}
+
+int cnss_pci_dev_ramdump(struct cnss_pci_data *pci_priv)
+{
+ int ret = 0;
+
+ if (!pci_priv) {
+ cnss_pr_err("pci_priv is NULL\n");
+ return -ENODEV;
+ }
+
+ switch (pci_priv->device_id) {
+ case QCA6174_DEVICE_ID:
+ ret = cnss_qca6174_ramdump(pci_priv);
+ break;
+ case QCA6290_EMULATION_DEVICE_ID:
+ case QCA6290_DEVICE_ID:
+ ret = cnss_qca6290_ramdump(pci_priv);
+ break;
+ default:
+ cnss_pr_err("Unknown device_id found: 0x%x\n",
+ pci_priv->device_id);
+ ret = -ENODEV;
+ }
+
+ return ret;
+}
+
+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_pci_data *pci_priv;
+
+ if (!plat_priv) {
+ cnss_pr_err("plat_priv is NULL\n");
+ return -ENODEV;
+ }
+
+ pci_priv = plat_priv->bus_priv;
+ if (!pci_priv) {
+ cnss_pr_err("pci_priv is NULL\n");
+ return -ENODEV;
+ }
+
+ if (pci_priv->driver_ops) {
+ cnss_pr_err("Driver has already registered\n");
+ return -EEXIST;
+ }
+
+ ret = cnss_driver_event_post(plat_priv,
+ CNSS_DRIVER_EVENT_REGISTER_DRIVER,
+ CNSS_EVENT_SYNC_UNINTERRUPTIBLE,
+ driver_ops);
+ return ret;
+}
+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);
+
+ if (!plat_priv) {
+ cnss_pr_err("plat_priv is NULL\n");
+ return;
+ }
+
+ cnss_driver_event_post(plat_priv,
+ CNSS_DRIVER_EVENT_UNREGISTER_DRIVER,
+ CNSS_EVENT_SYNC_UNINTERRUPTIBLE, NULL);
+}
+EXPORT_SYMBOL(cnss_wlan_unregister_driver);
+
+int cnss_pci_register_driver_hdlr(struct cnss_pci_data *pci_priv,
+ void *data)
+{
+ int ret = 0;
+ struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+
+ set_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state);
+ pci_priv->driver_ops = data;
+
+ ret = cnss_pci_dev_powerup(pci_priv);
+ if (ret) {
+ clear_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state);
+ pci_priv->driver_ops = NULL;
+ }
+
+ return ret;
+}
+
+int cnss_pci_unregister_driver_hdlr(struct cnss_pci_data *pci_priv)
+{
+ struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+
+ set_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state);
+ cnss_pci_dev_shutdown(pci_priv);
+ pci_priv->driver_ops = NULL;
+
+ return 0;
+}
+
static int cnss_pci_init_smmu(struct cnss_pci_data *pci_priv)
{
int ret = 0;
@@ -387,7 +914,7 @@ static int cnss_pci_suspend(struct device *dev)
if (!plat_priv)
goto out;
- driver_ops = plat_priv->driver_ops;
+ driver_ops = pci_priv->driver_ops;
if (driver_ops && driver_ops->suspend) {
ret = driver_ops->suspend(pci_dev, state);
if (ret) {
@@ -459,7 +986,7 @@ static int cnss_pci_resume(struct device *dev)
cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_RESUME);
}
- driver_ops = plat_priv->driver_ops;
+ driver_ops = pci_priv->driver_ops;
if (driver_ops && driver_ops->resume) {
ret = driver_ops->resume(pci_dev);
if (ret)
@@ -488,7 +1015,7 @@ static int cnss_pci_suspend_noirq(struct device *dev)
if (!plat_priv)
goto out;
- driver_ops = plat_priv->driver_ops;
+ driver_ops = pci_priv->driver_ops;
if (driver_ops && driver_ops->suspend_noirq)
ret = driver_ops->suspend_noirq(pci_dev);
@@ -511,7 +1038,7 @@ static int cnss_pci_resume_noirq(struct device *dev)
if (!plat_priv)
goto out;
- driver_ops = plat_priv->driver_ops;
+ driver_ops = pci_priv->driver_ops;
if (driver_ops && driver_ops->resume_noirq &&
!pci_priv->pci_link_down_ind)
ret = driver_ops->resume_noirq(pci_dev);
@@ -542,7 +1069,7 @@ static int cnss_pci_runtime_suspend(struct device *dev)
cnss_pr_dbg("Runtime suspend start\n");
- driver_ops = plat_priv->driver_ops;
+ driver_ops = pci_priv->driver_ops;
if (driver_ops && driver_ops->runtime_ops &&
driver_ops->runtime_ops->runtime_suspend)
ret = driver_ops->runtime_ops->runtime_suspend(pci_dev);
@@ -574,7 +1101,7 @@ static int cnss_pci_runtime_resume(struct device *dev)
cnss_pr_dbg("Runtime resume start\n");
- driver_ops = plat_priv->driver_ops;
+ driver_ops = pci_priv->driver_ops;
if (driver_ops && driver_ops->runtime_ops &&
driver_ops->runtime_ops->runtime_resume)
ret = driver_ops->runtime_ops->runtime_resume(pci_dev);
@@ -1054,13 +1581,19 @@ void cnss_get_msi_address(struct device *dev, u32 *msi_addr_low,
}
EXPORT_SYMBOL(cnss_get_msi_address);
+static char *get_wake_msi_name(void)
+{
+ return (char *)WAKE_MSI_NAME;
+}
+
u32 cnss_pci_get_wake_msi(struct cnss_pci_data *pci_priv)
{
int ret, num_vectors;
u32 user_base_data, base_vector;
+ char *wake_msi_name = get_wake_msi_name();
ret = cnss_get_user_msi_assignment(&pci_priv->pci_dev->dev,
- WAKE_MSI_NAME, &num_vectors,
+ wake_msi_name, &num_vectors,
&user_base_data, &base_vector);
if (ret) {
@@ -1286,8 +1819,8 @@ static void cnss_mhi_notify_status(enum MHI_CB_REASON reason, void *priv)
cnss_pr_dbg("MHI status cb is called with reason %d\n", reason);
- if (plat_priv->driver_ops && plat_priv->driver_ops->update_status)
- plat_priv->driver_ops->update_status(pci_priv->pci_dev,
+ if (pci_priv->driver_ops && pci_priv->driver_ops->update_status)
+ pci_priv->driver_ops->update_status(pci_priv->pci_dev,
CNSS_FW_DOWN);
set_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state);
diff --git a/drivers/net/wireless/cnss2/pci.h b/drivers/net/wireless/cnss2/pci.h
index b644d1e138e4..182355ae7577 100644
--- a/drivers/net/wireless/cnss2/pci.h
+++ b/drivers/net/wireless/cnss2/pci.h
@@ -62,6 +62,7 @@ struct cnss_pci_data {
const struct pci_device_id *pci_device_id;
u32 device_id;
u16 revision_id;
+ struct cnss_wlan_driver *driver_ops;
bool pci_link_state;
bool pci_link_down_ind;
struct pci_saved_state *saved_state;
@@ -155,5 +156,15 @@ int cnss_pm_request_resume(struct cnss_pci_data *pci_priv);
u32 cnss_pci_get_wake_msi(struct cnss_pci_data *pci_priv);
int cnss_pci_force_fw_assert_hdlr(struct cnss_pci_data *pci_priv);
void cnss_pci_fw_boot_timeout_hdlr(struct cnss_pci_data *pci_priv);
-
+int cnss_pci_call_driver_probe(struct cnss_pci_data *pci_priv);
+int cnss_pci_call_driver_remove(struct cnss_pci_data *pci_priv);
+int cnss_pci_dev_powerup(struct cnss_pci_data *pci_priv);
+int cnss_pci_dev_shutdown(struct cnss_pci_data *pci_priv);
+int cnss_pci_dev_crash_shutdown(struct cnss_pci_data *pci_priv);
+int cnss_pci_dev_ramdump(struct cnss_pci_data *pci_priv);
+int cnss_pci_register_driver_hdlr(struct cnss_pci_data *pci_priv, void *data);
+int cnss_pci_unregister_driver_hdlr(struct cnss_pci_data *pci_priv);
+int cnss_pci_call_driver_modem_status(struct cnss_pci_data *pci_priv,
+ int modem_current_status);
+int cnss_pci_recovery_update_status(struct cnss_pci_data *pci_priv);
#endif /* _CNSS_PCI_H */