Loading drivers/net/wireless/cnss2/bus.c +15 −0 Original line number Diff line number Diff line Loading @@ -448,6 +448,21 @@ int cnss_bus_check_link_status(struct cnss_plat_data *plat_priv) } } int cnss_bus_recover_link_down(struct cnss_plat_data *plat_priv) { if (!plat_priv) return -ENODEV; switch (plat_priv->bus_type) { case CNSS_BUS_PCI: return cnss_pci_recover_link_down(plat_priv->bus_priv); default: cnss_pr_dbg("Unsupported bus type: %d\n", plat_priv->bus_type); return -EINVAL; } } int cnss_bus_debug_reg_read(struct cnss_plat_data *plat_priv, u32 offset, u32 *val) { Loading drivers/net/wireless/cnss2/bus.h +1 −0 Original line number Diff line number Diff line Loading @@ -50,6 +50,7 @@ int cnss_bus_update_status(struct cnss_plat_data *plat_priv, enum cnss_driver_status status); int cnss_bus_is_device_down(struct cnss_plat_data *plat_priv); int cnss_bus_check_link_status(struct cnss_plat_data *plat_priv); int cnss_bus_recover_link_down(struct cnss_plat_data *plat_priv); int cnss_bus_debug_reg_read(struct cnss_plat_data *plat_priv, u32 offset, u32 *val); int cnss_bus_debug_reg_write(struct cnss_plat_data *plat_priv, u32 offset, Loading drivers/net/wireless/cnss2/main.c +9 −1 Original line number Diff line number Diff line Loading @@ -732,7 +732,7 @@ int cnss_idle_shutdown(struct device *dev) reinit_completion(&plat_priv->recovery_complete); ret = wait_for_completion_timeout(&plat_priv->recovery_complete, RECOVERY_TIMEOUT); msecs_to_jiffies(RECOVERY_TIMEOUT)); if (!ret) { cnss_pr_err("Timeout waiting for recovery to complete\n"); CNSS_ASSERT(0); Loading Loading @@ -1083,6 +1083,14 @@ static int cnss_do_recovery(struct cnss_plat_data *plat_priv, if (test_bit(LINK_DOWN_SELF_RECOVERY, &plat_priv->ctrl_params.quirks)) goto self_recovery; if (!cnss_bus_recover_link_down(plat_priv)) { /* clear recovery bit here to avoid skipping * the recovery work for RDDM later */ clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state); return 0; } break; case CNSS_REASON_RDDM: cnss_bus_collect_dump_info(plat_priv, false); Loading drivers/net/wireless/cnss2/pci.c +56 −14 Original line number Diff line number Diff line Loading @@ -46,6 +46,7 @@ #define WAKE_MSI_NAME "WAKE" #define DEV_RDDM_TIMEOUT 5000 #define WAKE_EVENT_TIMEOUT 5000 #ifdef CONFIG_CNSS_EMULATION #define EMULATION_HW 1 Loading Loading @@ -826,6 +827,42 @@ int cnss_resume_pci_link(struct cnss_pci_data *pci_priv) return ret; } int cnss_pci_recover_link_down(struct cnss_pci_data *pci_priv) { int ret; switch (pci_priv->device_id) { case QCA6390_DEVICE_ID: case QCA6490_DEVICE_ID: break; default: return -EOPNOTSUPP; } /* Always wait here to avoid missing WAKE assert for RDDM * before link recovery */ msleep(WAKE_EVENT_TIMEOUT); ret = cnss_suspend_pci_link(pci_priv); if (ret) cnss_pr_err("Failed to suspend PCI link, err = %d\n", ret); ret = cnss_resume_pci_link(pci_priv); if (ret) { cnss_pr_err("Failed to resume PCI link, err = %d\n", ret); del_timer(&pci_priv->dev_rddm_timer); return ret; } mod_timer(&pci_priv->dev_rddm_timer, jiffies + msecs_to_jiffies(DEV_RDDM_TIMEOUT)); mhi_debug_reg_dump(pci_priv->mhi_ctrl); return 0; } int cnss_pci_prevent_l1(struct device *dev) { struct pci_dev *pci_dev = to_pci_dev(dev); Loading Loading @@ -900,6 +937,7 @@ int cnss_pci_link_down(struct device *dev) pci_priv->pci_link_down_ind = true; spin_unlock_irqrestore(&pci_link_down_lock, flags); reinit_completion(&pci_priv->wake_event); cnss_pr_err("PCI link down is detected, schedule recovery\n"); cnss_schedule_recovery(dev, CNSS_REASON_LINK_DOWN); Loading Loading @@ -2384,23 +2422,25 @@ static void cnss_pci_event_cb(struct msm_pcie_notify *notify) case MSM_PCIE_EVENT_LINKDOWN: if (test_bit(ENABLE_PCI_LINK_DOWN_PANIC, &plat_priv->ctrl_params.quirks)) panic("cnss: PCI link is down!\n"); panic("cnss: PCI link is down\n"); spin_lock_irqsave(&pci_link_down_lock, flags); if (pci_priv->pci_link_down_ind) { cnss_pr_dbg("PCI link down recovery is in progress, ignore!\n"); cnss_pr_dbg("PCI link down recovery is in progress, ignore\n"); spin_unlock_irqrestore(&pci_link_down_lock, flags); return; } pci_priv->pci_link_down_ind = true; spin_unlock_irqrestore(&pci_link_down_lock, flags); cnss_fatal_err("PCI link down, schedule recovery!\n"); reinit_completion(&pci_priv->wake_event); cnss_fatal_err("PCI link down, schedule recovery\n"); if (pci_dev->device == QCA6174_DEVICE_ID) disable_irq(pci_dev->irq); cnss_schedule_recovery(&pci_dev->dev, CNSS_REASON_LINK_DOWN); break; case MSM_PCIE_EVENT_WAKEUP: complete(&pci_priv->wake_event); if (cnss_pci_get_monitor_wake_intr(pci_priv) && cnss_pci_get_auto_suspended(pci_priv)) { cnss_pci_set_monitor_wake_intr(pci_priv, false); Loading Loading @@ -3790,18 +3830,21 @@ static int cnss_pci_enable_bus(struct cnss_pci_data *pci_priv) goto release_region; } pci_set_master(pci_dev); pci_priv->bar = pci_iomap(pci_dev, PCI_BAR_NUM, 0); if (!pci_priv->bar) { cnss_pr_err("Failed to do PCI IO map!\n"); ret = -EIO; goto clear_master; goto release_region; } /* Save default config space without BME enabled */ pci_save_state(pci_dev); pci_priv->default_state = pci_store_saved_state(pci_dev); pci_set_master(pci_dev); return 0; clear_master: pci_clear_master(pci_dev); release_region: pci_release_region(pci_dev, PCI_BAR_NUM); disable_device: Loading @@ -3814,12 +3857,14 @@ static void cnss_pci_disable_bus(struct cnss_pci_data *pci_priv) { struct pci_dev *pci_dev = pci_priv->pci_dev; pci_clear_master(pci_dev); pci_load_and_free_saved_state(pci_dev, &pci_priv->saved_state); if (pci_priv->bar) { pci_iounmap(pci_dev, pci_priv->bar); pci_priv->bar = NULL; } pci_clear_master(pci_dev); pci_release_region(pci_dev, PCI_BAR_NUM); if (pci_is_enabled(pci_dev)) pci_disable_device(pci_dev); Loading Loading @@ -4621,9 +4666,6 @@ static int cnss_pci_probe(struct pci_dev *pci_dev, if (ret) goto dereg_pci_event; pci_save_state(pci_dev); pci_priv->default_state = pci_store_saved_state(pci_dev); switch (pci_dev->device) { case QCA6174_DEVICE_ID: pci_read_config_word(pci_dev, QCA6174_REV_ID_OFFSET, Loading @@ -4640,6 +4682,7 @@ static int cnss_pci_probe(struct pci_dev *pci_dev, cnss_pci_set_wlaon_pwr_ctrl(pci_priv, false, false, false); timer_setup(&pci_priv->dev_rddm_timer, cnss_dev_rddm_timeout_hdlr, 0); init_completion(&pci_priv->wake_event); INIT_DELAYED_WORK(&pci_priv->time_sync_work, cnss_pci_time_sync_work_hdlr); Loading Loading @@ -4703,14 +4746,13 @@ static void cnss_pci_remove(struct pci_dev *pci_dev) case QCA6490_DEVICE_ID: cnss_pci_unregister_mhi(pci_priv); cnss_pci_disable_msi(pci_priv); complete_all(&pci_priv->wake_event); del_timer(&pci_priv->dev_rddm_timer); break; default: break; } pci_load_and_free_saved_state(pci_dev, &pci_priv->saved_state); cnss_pci_disable_bus(pci_priv); cnss_dereg_pci_event(pci_priv); cnss_pci_deinit_smmu(pci_priv); Loading drivers/net/wireless/cnss2/pci.h +2 −0 Original line number Diff line number Diff line Loading @@ -76,6 +76,7 @@ struct cnss_pci_data { u8 drv_connected_last; u16 def_link_speed; u16 def_link_width; struct completion wake_event; u8 monitor_wake_intr; struct iommu_domain *iommu_domain; u8 smmu_s1_enable; Loading Loading @@ -164,6 +165,7 @@ static inline int cnss_pci_get_drv_connected(void *bus_priv) int cnss_pci_check_link_status(struct cnss_pci_data *pci_priv); int cnss_suspend_pci_link(struct cnss_pci_data *pci_priv); int cnss_resume_pci_link(struct cnss_pci_data *pci_priv); int cnss_pci_recover_link_down(struct cnss_pci_data *pci_priv); int cnss_pci_init(struct cnss_plat_data *plat_priv); void cnss_pci_deinit(struct cnss_plat_data *plat_priv); int cnss_pci_alloc_fw_mem(struct cnss_pci_data *pci_priv); Loading Loading
drivers/net/wireless/cnss2/bus.c +15 −0 Original line number Diff line number Diff line Loading @@ -448,6 +448,21 @@ int cnss_bus_check_link_status(struct cnss_plat_data *plat_priv) } } int cnss_bus_recover_link_down(struct cnss_plat_data *plat_priv) { if (!plat_priv) return -ENODEV; switch (plat_priv->bus_type) { case CNSS_BUS_PCI: return cnss_pci_recover_link_down(plat_priv->bus_priv); default: cnss_pr_dbg("Unsupported bus type: %d\n", plat_priv->bus_type); return -EINVAL; } } int cnss_bus_debug_reg_read(struct cnss_plat_data *plat_priv, u32 offset, u32 *val) { Loading
drivers/net/wireless/cnss2/bus.h +1 −0 Original line number Diff line number Diff line Loading @@ -50,6 +50,7 @@ int cnss_bus_update_status(struct cnss_plat_data *plat_priv, enum cnss_driver_status status); int cnss_bus_is_device_down(struct cnss_plat_data *plat_priv); int cnss_bus_check_link_status(struct cnss_plat_data *plat_priv); int cnss_bus_recover_link_down(struct cnss_plat_data *plat_priv); int cnss_bus_debug_reg_read(struct cnss_plat_data *plat_priv, u32 offset, u32 *val); int cnss_bus_debug_reg_write(struct cnss_plat_data *plat_priv, u32 offset, Loading
drivers/net/wireless/cnss2/main.c +9 −1 Original line number Diff line number Diff line Loading @@ -732,7 +732,7 @@ int cnss_idle_shutdown(struct device *dev) reinit_completion(&plat_priv->recovery_complete); ret = wait_for_completion_timeout(&plat_priv->recovery_complete, RECOVERY_TIMEOUT); msecs_to_jiffies(RECOVERY_TIMEOUT)); if (!ret) { cnss_pr_err("Timeout waiting for recovery to complete\n"); CNSS_ASSERT(0); Loading Loading @@ -1083,6 +1083,14 @@ static int cnss_do_recovery(struct cnss_plat_data *plat_priv, if (test_bit(LINK_DOWN_SELF_RECOVERY, &plat_priv->ctrl_params.quirks)) goto self_recovery; if (!cnss_bus_recover_link_down(plat_priv)) { /* clear recovery bit here to avoid skipping * the recovery work for RDDM later */ clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state); return 0; } break; case CNSS_REASON_RDDM: cnss_bus_collect_dump_info(plat_priv, false); Loading
drivers/net/wireless/cnss2/pci.c +56 −14 Original line number Diff line number Diff line Loading @@ -46,6 +46,7 @@ #define WAKE_MSI_NAME "WAKE" #define DEV_RDDM_TIMEOUT 5000 #define WAKE_EVENT_TIMEOUT 5000 #ifdef CONFIG_CNSS_EMULATION #define EMULATION_HW 1 Loading Loading @@ -826,6 +827,42 @@ int cnss_resume_pci_link(struct cnss_pci_data *pci_priv) return ret; } int cnss_pci_recover_link_down(struct cnss_pci_data *pci_priv) { int ret; switch (pci_priv->device_id) { case QCA6390_DEVICE_ID: case QCA6490_DEVICE_ID: break; default: return -EOPNOTSUPP; } /* Always wait here to avoid missing WAKE assert for RDDM * before link recovery */ msleep(WAKE_EVENT_TIMEOUT); ret = cnss_suspend_pci_link(pci_priv); if (ret) cnss_pr_err("Failed to suspend PCI link, err = %d\n", ret); ret = cnss_resume_pci_link(pci_priv); if (ret) { cnss_pr_err("Failed to resume PCI link, err = %d\n", ret); del_timer(&pci_priv->dev_rddm_timer); return ret; } mod_timer(&pci_priv->dev_rddm_timer, jiffies + msecs_to_jiffies(DEV_RDDM_TIMEOUT)); mhi_debug_reg_dump(pci_priv->mhi_ctrl); return 0; } int cnss_pci_prevent_l1(struct device *dev) { struct pci_dev *pci_dev = to_pci_dev(dev); Loading Loading @@ -900,6 +937,7 @@ int cnss_pci_link_down(struct device *dev) pci_priv->pci_link_down_ind = true; spin_unlock_irqrestore(&pci_link_down_lock, flags); reinit_completion(&pci_priv->wake_event); cnss_pr_err("PCI link down is detected, schedule recovery\n"); cnss_schedule_recovery(dev, CNSS_REASON_LINK_DOWN); Loading Loading @@ -2384,23 +2422,25 @@ static void cnss_pci_event_cb(struct msm_pcie_notify *notify) case MSM_PCIE_EVENT_LINKDOWN: if (test_bit(ENABLE_PCI_LINK_DOWN_PANIC, &plat_priv->ctrl_params.quirks)) panic("cnss: PCI link is down!\n"); panic("cnss: PCI link is down\n"); spin_lock_irqsave(&pci_link_down_lock, flags); if (pci_priv->pci_link_down_ind) { cnss_pr_dbg("PCI link down recovery is in progress, ignore!\n"); cnss_pr_dbg("PCI link down recovery is in progress, ignore\n"); spin_unlock_irqrestore(&pci_link_down_lock, flags); return; } pci_priv->pci_link_down_ind = true; spin_unlock_irqrestore(&pci_link_down_lock, flags); cnss_fatal_err("PCI link down, schedule recovery!\n"); reinit_completion(&pci_priv->wake_event); cnss_fatal_err("PCI link down, schedule recovery\n"); if (pci_dev->device == QCA6174_DEVICE_ID) disable_irq(pci_dev->irq); cnss_schedule_recovery(&pci_dev->dev, CNSS_REASON_LINK_DOWN); break; case MSM_PCIE_EVENT_WAKEUP: complete(&pci_priv->wake_event); if (cnss_pci_get_monitor_wake_intr(pci_priv) && cnss_pci_get_auto_suspended(pci_priv)) { cnss_pci_set_monitor_wake_intr(pci_priv, false); Loading Loading @@ -3790,18 +3830,21 @@ static int cnss_pci_enable_bus(struct cnss_pci_data *pci_priv) goto release_region; } pci_set_master(pci_dev); pci_priv->bar = pci_iomap(pci_dev, PCI_BAR_NUM, 0); if (!pci_priv->bar) { cnss_pr_err("Failed to do PCI IO map!\n"); ret = -EIO; goto clear_master; goto release_region; } /* Save default config space without BME enabled */ pci_save_state(pci_dev); pci_priv->default_state = pci_store_saved_state(pci_dev); pci_set_master(pci_dev); return 0; clear_master: pci_clear_master(pci_dev); release_region: pci_release_region(pci_dev, PCI_BAR_NUM); disable_device: Loading @@ -3814,12 +3857,14 @@ static void cnss_pci_disable_bus(struct cnss_pci_data *pci_priv) { struct pci_dev *pci_dev = pci_priv->pci_dev; pci_clear_master(pci_dev); pci_load_and_free_saved_state(pci_dev, &pci_priv->saved_state); if (pci_priv->bar) { pci_iounmap(pci_dev, pci_priv->bar); pci_priv->bar = NULL; } pci_clear_master(pci_dev); pci_release_region(pci_dev, PCI_BAR_NUM); if (pci_is_enabled(pci_dev)) pci_disable_device(pci_dev); Loading Loading @@ -4621,9 +4666,6 @@ static int cnss_pci_probe(struct pci_dev *pci_dev, if (ret) goto dereg_pci_event; pci_save_state(pci_dev); pci_priv->default_state = pci_store_saved_state(pci_dev); switch (pci_dev->device) { case QCA6174_DEVICE_ID: pci_read_config_word(pci_dev, QCA6174_REV_ID_OFFSET, Loading @@ -4640,6 +4682,7 @@ static int cnss_pci_probe(struct pci_dev *pci_dev, cnss_pci_set_wlaon_pwr_ctrl(pci_priv, false, false, false); timer_setup(&pci_priv->dev_rddm_timer, cnss_dev_rddm_timeout_hdlr, 0); init_completion(&pci_priv->wake_event); INIT_DELAYED_WORK(&pci_priv->time_sync_work, cnss_pci_time_sync_work_hdlr); Loading Loading @@ -4703,14 +4746,13 @@ static void cnss_pci_remove(struct pci_dev *pci_dev) case QCA6490_DEVICE_ID: cnss_pci_unregister_mhi(pci_priv); cnss_pci_disable_msi(pci_priv); complete_all(&pci_priv->wake_event); del_timer(&pci_priv->dev_rddm_timer); break; default: break; } pci_load_and_free_saved_state(pci_dev, &pci_priv->saved_state); cnss_pci_disable_bus(pci_priv); cnss_dereg_pci_event(pci_priv); cnss_pci_deinit_smmu(pci_priv); Loading
drivers/net/wireless/cnss2/pci.h +2 −0 Original line number Diff line number Diff line Loading @@ -76,6 +76,7 @@ struct cnss_pci_data { u8 drv_connected_last; u16 def_link_speed; u16 def_link_width; struct completion wake_event; u8 monitor_wake_intr; struct iommu_domain *iommu_domain; u8 smmu_s1_enable; Loading Loading @@ -164,6 +165,7 @@ static inline int cnss_pci_get_drv_connected(void *bus_priv) int cnss_pci_check_link_status(struct cnss_pci_data *pci_priv); int cnss_suspend_pci_link(struct cnss_pci_data *pci_priv); int cnss_resume_pci_link(struct cnss_pci_data *pci_priv); int cnss_pci_recover_link_down(struct cnss_pci_data *pci_priv); int cnss_pci_init(struct cnss_plat_data *plat_priv); void cnss_pci_deinit(struct cnss_plat_data *plat_priv); int cnss_pci_alloc_fw_mem(struct cnss_pci_data *pci_priv); Loading