From 9a3821168df3d40f5721107578d2122e18171b6f Mon Sep 17 00:00:00 2001 From: Yue Ma Date: Wed, 27 Jun 2018 16:17:37 +0530 Subject: [PATCH] cnss2: Refactor PCIe bus related code PCIe bus related APIs should not directly called from common files. Instead, create equivalent abstract BUS APIs from where it can decide which corresponding PCIe bus APIs to be invoked. This will help to extend other buses like USB and SDIO in the future. Change-Id: I1f115173f2e6c34e3a8cb6f975349112f52697e4 Signed-off-by: Yue Ma Signed-off-by: Rajasekaran Kalidoss --- drivers/net/wireless/cnss2/bus.c | 192 ++++++++++ drivers/net/wireless/cnss2/bus.h | 14 +- drivers/net/wireless/cnss2/main.c | 567 ++---------------------------- drivers/net/wireless/cnss2/main.h | 14 +- drivers/net/wireless/cnss2/pci.c | 551 ++++++++++++++++++++++++++++- drivers/net/wireless/cnss2/pci.h | 13 +- 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 #include #include +#include #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 */