diff --git a/drivers/net/wireless/cnss2/main.c b/drivers/net/wireless/cnss2/main.c index 29bfe1f4d6ed..f96f8136e097 100644 --- a/drivers/net/wireless/cnss2/main.c +++ b/drivers/net/wireless/cnss2/main.c @@ -573,7 +573,7 @@ static int cnss_driver_call_probe(struct cnss_plat_data *plat_priv) struct cnss_pci_data *pci_priv = plat_priv->bus_priv; if (!plat_priv->driver_ops) { - cnss_pr_err("driver_ops is NULL!"); + cnss_pr_err("driver_ops is NULL\n"); ret = -EINVAL; goto out; } @@ -587,7 +587,7 @@ static int cnss_driver_call_probe(struct cnss_plat_data *plat_priv) goto out; } clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state); - } else { + } 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) { @@ -605,6 +605,25 @@ 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 (!plat_priv->driver_ops) { + cnss_pr_err("driver_ops is NULL\n"); + return -EINVAL; + } + + if (test_bit(CNSS_DRIVER_RECOVERY, &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; @@ -626,8 +645,11 @@ static int cnss_fw_ready_hdlr(struct cnss_plat_data *plat_priv) } else if (test_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state)) { ret = cnss_wlfw_wlan_mode_send_sync(plat_priv, QMI_WLFW_CALIBRATION_V01); - } else { + } 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); + } else { + complete(&plat_priv->power_up_complete); } if (ret) @@ -668,6 +690,10 @@ static char *cnss_driver_event_to_str(enum cnss_driver_event_type type) return "RECOVERY"; case CNSS_DRIVER_EVENT_FORCE_FW_ASSERT: return "FORCE_FW_ASSERT"; + case CNSS_DRIVER_EVENT_POWER_UP: + return "POWER_UP"; + case CNSS_DRIVER_EVENT_POWER_DOWN: + return "POWER_DOWN"; case CNSS_DRIVER_EVENT_MAX: return "EVENT_MAX"; } @@ -746,64 +772,57 @@ out: int cnss_power_up(struct device *dev) { int ret = 0; - void *bus_priv = cnss_bus_dev_to_bus_priv(dev); struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev); + unsigned int timeout; - if (!bus_priv || !plat_priv) + if (!plat_priv) { + cnss_pr_err("plat_priv is NULL\n"); return -ENODEV; - - if (plat_priv->device_id != QCA6174_DEVICE_ID) { - cnss_pr_dbg("Power up is not supported for device ID 0x%lx\n", - plat_priv->device_id); - return 0; } - ret = cnss_power_on_device(plat_priv); - if (ret) { - cnss_pr_err("Failed to power on device, err = %d\n", ret); - goto err_power_on; - } + cnss_pr_dbg("Powering up device\n"); - ret = cnss_resume_pci_link(bus_priv); - if (ret) { - cnss_pr_err("Failed to resume PCI link, err = %d\n", ret); - goto err_resume_link; + ret = cnss_driver_event_post(plat_priv, + CNSS_DRIVER_EVENT_POWER_UP, + true, NULL); + if (ret) + goto out; + + if (plat_priv->device_id == QCA6174_DEVICE_ID) + goto out; + + timeout = cnss_get_qmi_timeout(); + + reinit_completion(&plat_priv->power_up_complete); + ret = wait_for_completion_timeout(&plat_priv->power_up_complete, + msecs_to_jiffies(timeout) << 2); + if (!ret) { + cnss_pr_err("Timeout waiting for power up to complete\n"); + ret = -EAGAIN; + goto out; } return 0; -err_resume_link: - cnss_power_off_device(plat_priv); -err_power_on: + +out: return ret; } EXPORT_SYMBOL(cnss_power_up); int cnss_power_down(struct device *dev) { - int ret = 0; - void *bus_priv = cnss_bus_dev_to_bus_priv(dev); struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev); - if (!bus_priv || !plat_priv) + if (!plat_priv) { + cnss_pr_err("plat_priv is NULL\n"); return -ENODEV; - - if (plat_priv->device_id != QCA6174_DEVICE_ID) { - cnss_pr_dbg("Power down is not supported for device ID 0x%lx\n", - plat_priv->device_id); - return 0; } - cnss_request_bus_bandwidth(CNSS_BUS_WIDTH_NONE); - cnss_pci_set_monitor_wake_intr(bus_priv, false); - cnss_pci_set_auto_suspended(bus_priv, 0); + cnss_pr_dbg("Powering down device\n"); - ret = cnss_suspend_pci_link(bus_priv); - if (ret) - cnss_pr_err("Failed to suspend PCI link, err = %d\n", ret); - - cnss_power_off_device(plat_priv); - - return 0; + return cnss_driver_event_post(plat_priv, + CNSS_DRIVER_EVENT_POWER_DOWN, + true, NULL); } EXPORT_SYMBOL(cnss_power_down); @@ -1024,14 +1043,11 @@ static int cnss_qca6174_shutdown(struct cnss_plat_data *plat_priv) if (!plat_priv->driver_ops) return -EINVAL; - if (test_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state)) { - cnss_request_bus_bandwidth(CNSS_BUS_WIDTH_NONE); - plat_priv->driver_ops->remove(pci_priv->pci_dev); - cnss_pci_set_monitor_wake_intr(pci_priv, false); - cnss_pci_set_auto_suspended(pci_priv, 0); - } else { - plat_priv->driver_ops->shutdown(pci_priv->pci_dev); - } + cnss_driver_call_remove(plat_priv); + + cnss_request_bus_bandwidth(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) @@ -1039,10 +1055,7 @@ static int cnss_qca6174_shutdown(struct cnss_plat_data *plat_priv) cnss_power_off_device(plat_priv); - if (test_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state)) { - clear_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state); - clear_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state); - } + clear_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state); return ret; } @@ -1134,16 +1147,13 @@ static int cnss_qca6290_shutdown(struct cnss_plat_data *plat_priv) if (!plat_priv->driver_ops) return -EINVAL; - if (test_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state)) { - cnss_request_bus_bandwidth(CNSS_BUS_WIDTH_NONE); - plat_priv->driver_ops->remove(pci_priv->pci_dev); - cnss_pci_set_monitor_wake_intr(pci_priv, false); - cnss_pci_set_auto_suspended(pci_priv, 0); - } else { - plat_priv->driver_ops->shutdown(pci_priv->pci_dev); - } + cnss_driver_call_remove(plat_priv); skip_driver_remove: + cnss_request_bus_bandwidth(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); @@ -1154,11 +1164,7 @@ skip_driver_remove: clear_bit(CNSS_FW_READY, &plat_priv->driver_state); clear_bit(CNSS_FW_MEM_READY, &plat_priv->driver_state); - - if (test_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state)) { - clear_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state); - clear_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state); - } + clear_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state); return ret; } @@ -1661,6 +1667,22 @@ static int cnss_cold_boot_cal_done_hdlr(struct cnss_plat_data *plat_priv) return 0; } +static int cnss_power_up_hdlr(struct cnss_plat_data *plat_priv) +{ + struct cnss_subsys_info *subsys_info = &plat_priv->subsys_info; + + return cnss_powerup(&subsys_info->subsys_desc); +} + +static int cnss_power_down_hdlr(struct cnss_plat_data *plat_priv) +{ + struct cnss_subsys_info *subsys_info = &plat_priv->subsys_info; + + cnss_shutdown(&subsys_info->subsys_desc, false); + + return 0; +} + static void cnss_driver_event_work(struct work_struct *work) { struct cnss_plat_data *plat_priv = @@ -1728,6 +1750,12 @@ static void cnss_driver_event_work(struct work_struct *work) case CNSS_DRIVER_EVENT_FORCE_FW_ASSERT: ret = cnss_force_fw_assert_hdlr(plat_priv); break; + case CNSS_DRIVER_EVENT_POWER_UP: + ret = cnss_power_up_hdlr(plat_priv); + break; + case CNSS_DRIVER_EVENT_POWER_DOWN: + ret = cnss_power_down_hdlr(plat_priv); + break; default: cnss_pr_err("Invalid driver event type: %d", event->type); @@ -2226,6 +2254,8 @@ static int cnss_probe(struct platform_device *plat_dev) cnss_pr_err("Failed to init platform device wakeup source, err = %d\n", ret); + init_completion(&plat_priv->power_up_complete); + cnss_pr_info("Platform driver probed successfully.\n"); return 0; @@ -2257,6 +2287,7 @@ static int cnss_remove(struct platform_device *plat_dev) { struct cnss_plat_data *plat_priv = platform_get_drvdata(plat_dev); + complete_all(&plat_priv->power_up_complete); device_init_wakeup(&plat_dev->dev, false); unregister_pm_notifier(&cnss_pm_notifier); del_timer(&plat_priv->fw_boot_timer); diff --git a/drivers/net/wireless/cnss2/main.h b/drivers/net/wireless/cnss2/main.h index e3a8d0cccd52..35cabda61b03 100644 --- a/drivers/net/wireless/cnss2/main.h +++ b/drivers/net/wireless/cnss2/main.h @@ -126,6 +126,8 @@ enum cnss_driver_event_type { CNSS_DRIVER_EVENT_UNREGISTER_DRIVER, CNSS_DRIVER_EVENT_RECOVERY, CNSS_DRIVER_EVENT_FORCE_FW_ASSERT, + CNSS_DRIVER_EVENT_POWER_UP, + CNSS_DRIVER_EVENT_POWER_DOWN, CNSS_DRIVER_EVENT_MAX, }; @@ -201,6 +203,7 @@ struct cnss_plat_data { struct dentry *root_dentry; atomic_t pm_count; struct timer_list fw_boot_timer; + struct completion power_up_complete; }; void *cnss_bus_dev_to_bus_priv(struct device *dev);