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 */