Loading drivers/net/wireless/ath/wil6210/main.c +22 −10 Original line number Diff line number Diff line Loading @@ -536,23 +536,16 @@ bool wil_is_recovery_blocked(struct wil6210_priv *wil) return no_fw_recovery && (wil->recovery_state == fw_recovery_pending); } static void wil_fw_error_worker(struct work_struct *work) void wil_fw_recovery(struct wil6210_priv *wil) { struct wil6210_priv *wil = container_of(work, struct wil6210_priv, fw_error_worker); struct net_device *ndev = wil->main_ndev; struct wireless_dev *wdev; wil_dbg_misc(wil, "fw error worker\n"); if (!ndev || !(ndev->flags & IFF_UP)) { wil_info(wil, "No recovery - interface is down\n"); return; } wil_dbg_misc(wil, "fw recovery\n"); wdev = ndev->ieee80211_ptr; /* increment @recovery_count if less then WIL6210_FW_RECOVERY_TO /* increment @recovery_count if less than WIL6210_FW_RECOVERY_TO * passed since last recovery attempt */ if (time_is_after_jiffies(wil->last_fw_recovery + Loading Loading @@ -612,6 +605,22 @@ static void wil_fw_error_worker(struct work_struct *work) rtnl_unlock(); } static void wil_fw_error_worker(struct work_struct *work) { struct wil6210_priv *wil = container_of(work, struct wil6210_priv, fw_error_worker); struct net_device *ndev = wil->main_ndev; wil_dbg_misc(wil, "fw error worker\n"); if (!ndev || !(ndev->flags & IFF_UP)) { wil_info(wil, "No recovery - interface is down\n"); return; } wil_fw_recovery(wil); } static int wil_find_free_ring(struct wil6210_priv *wil) { int i; Loading Loading @@ -724,6 +733,8 @@ int wil_priv_init(struct wil6210_priv *wil) INIT_WORK(&wil->wmi_event_worker, wmi_event_worker); INIT_WORK(&wil->fw_error_worker, wil_fw_error_worker); INIT_WORK(&wil->pci_linkdown_recovery_worker, wil_pci_linkdown_recovery_worker); INIT_LIST_HEAD(&wil->pending_wmi_ev); spin_lock_init(&wil->wmi_ev_lock); Loading Loading @@ -839,6 +850,7 @@ void wil_priv_deinit(struct wil6210_priv *wil) wil_set_recovery_state(wil, fw_recovery_idle); cancel_work_sync(&wil->fw_error_worker); cancel_work_sync(&wil->pci_linkdown_recovery_worker); wmi_event_flush(wil); destroy_workqueue(wil->wq_service); destroy_workqueue(wil->wmi_wq); Loading drivers/net/wireless/ath/wil6210/pcie_bus.c +109 −1 Original line number Diff line number Diff line /* * Copyright (c) 2012-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018, The Linux Foundation. All rights reserved. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above Loading Loading @@ -298,6 +298,108 @@ static int wil_platform_rop_fw_recovery(void *wil_handle) return 0; } void wil_pci_linkdown_recovery_worker(struct work_struct *work) { struct wil6210_priv *wil = container_of(work, struct wil6210_priv, pci_linkdown_recovery_worker); int rc, i; struct wil6210_vif *vif; struct net_device *ndev = wil->main_ndev; wil_dbg_misc(wil, "starting pci_linkdown recovery\n"); rtnl_lock(); mutex_lock(&wil->mutex); down_write(&wil->mem_lock); clear_bit(wil_status_fwready, wil->status); set_bit(wil_status_pci_linkdown, wil->status); set_bit(wil_status_resetting, wil->status); up_write(&wil->mem_lock); if (test_and_clear_bit(wil_status_napi_en, wil->status)) { napi_disable(&wil->napi_rx); napi_disable(&wil->napi_tx); } mutex_unlock(&wil->mutex); rtnl_unlock(); mutex_lock(&wil->mutex); mutex_lock(&wil->vif_mutex); wil_ftm_stop_operations(wil); wil_p2p_stop_radio_operations(wil); wil_abort_scan_all_vifs(wil, false); mutex_unlock(&wil->vif_mutex); for (i = 0; i < wil->max_vifs; i++) { vif = wil->vifs[i]; if (vif) { cancel_work_sync(&vif->disconnect_worker); wil6210_disconnect(vif, NULL, WLAN_REASON_DEAUTH_LEAVING); } } wmi_event_flush(wil); flush_workqueue(wil->wq_service); flush_workqueue(wil->wmi_wq); /* Recover PCIe */ if (wil->platform_ops.pci_linkdown_recovery) { rc = wil->platform_ops.pci_linkdown_recovery( wil->platform_handle); if (rc) { wil_err(wil, "platform device failed to recover from pci linkdown (%d)\n", rc); mutex_unlock(&wil->mutex); goto out; } } else { wil_err(wil, "platform device doesn't support pci_linkdown recovery\n"); mutex_unlock(&wil->mutex); goto out; } if (!ndev || !(ndev->flags & IFF_UP)) { wil_reset(wil, false); mutex_unlock(&wil->mutex); } else { mutex_unlock(&wil->mutex); wil->recovery_state = fw_recovery_pending; wil_fw_recovery(wil); } out: return; } static int wil_platform_rop_notify(void *wil_handle, enum wil_platform_notif notif) { struct wil6210_priv *wil = wil_handle; if (!wil) return -EINVAL; switch (notif) { case WIL_PLATFORM_NOTIF_PCI_LINKDOWN: wil_info(wil, "received WIL_PLATFORM_NOTIF_PCI_LINKDOWN\n"); clear_bit(wil_status_fwready, wil->status); set_bit(wil_status_resetting, wil->status); set_bit(wil_status_pci_linkdown, wil->status); schedule_work(&wil->pci_linkdown_recovery_worker); break; default: break; } return 0; } static void wil_platform_ops_uninit(struct wil6210_priv *wil) { if (wil->platform_ops.uninit) Loading @@ -313,6 +415,7 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) const struct wil_platform_rops rops = { .ramdump = wil_platform_rop_ramdump, .fw_recovery = wil_platform_rop_fw_recovery, .notify = wil_platform_rop_notify, }; u32 bar_size = pci_resource_len(pdev, 0); int dma_addr_size[] = {64, 48, 40, 32}; /* keep descending order */ Loading Loading @@ -560,6 +663,11 @@ static int wil6210_resume(struct device *dev, bool is_runtime) struct wil6210_priv *wil = pci_get_drvdata(pdev); bool keep_radio_on, active_ifaces; if (test_bit(wil_status_pci_linkdown, wil->status)) { wil_dbg_pm(wil, "ignore resume during pci linkdown\n"); return 0; } wil_dbg_pm(wil, "resume: %s\n", is_runtime ? "runtime" : "system"); mutex_lock(&wil->vif_mutex); Loading drivers/net/wireless/ath/wil6210/pm.c +6 −0 Original line number Diff line number Diff line Loading @@ -101,6 +101,12 @@ int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime) goto out; } if (test_bit(wil_status_pci_linkdown, wil->status)) { wil_dbg_pm(wil, "Delay suspend during pci linkdown\n"); rc = -EBUSY; goto out; } mutex_lock(&wil->vif_mutex); active_ifaces = wil_has_active_ifaces(wil, true, false); mutex_unlock(&wil->vif_mutex); Loading drivers/net/wireless/ath/wil6210/wil6210.h +6 −0 Original line number Diff line number Diff line Loading @@ -661,6 +661,7 @@ enum { /* for wil6210_priv.status */ wil_status_suspending, /* suspend in progress */ wil_status_suspended, /* suspend completed, device is suspended */ wil_status_resuming, /* resume in progress */ wil_status_pci_linkdown, /* pci linkdown occurred */ wil_status_last /* keep last */ }; Loading Loading @@ -1074,6 +1075,8 @@ struct wil6210_priv { u32 max_ampdu_size; struct wil_fw_stats_global fw_stats_global; struct work_struct pci_linkdown_recovery_worker; }; #define wil_to_wiphy(i) (i->wiphy) Loading Loading @@ -1365,6 +1368,9 @@ void wil_disconnect_worker(struct work_struct *work); void wil_init_txrx_ops(struct wil6210_priv *wil); void wil_fw_recovery(struct wil6210_priv *wil); void wil_pci_linkdown_recovery_worker(struct work_struct *work); /* TX API */ int wil_ring_init_tx(struct wil6210_vif *vif, int cid); int wil_vring_init_bcast(struct wil6210_vif *vif, int id, int size); Loading drivers/net/wireless/ath/wil6210/wil_platform.h +9 −0 Original line number Diff line number Diff line /* * Copyright (c) 2014-2017 Qualcomm Atheros, Inc. * Copyright (c) 2019, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above Loading Loading @@ -27,6 +28,10 @@ enum wil_platform_event { WIL_PLATFORM_EVT_POST_SUSPEND = 4, }; enum wil_platform_notif { WIL_PLATFORM_NOTIF_PCI_LINKDOWN = 0, }; enum wil_platform_features { WIL_PLATFORM_FEATURE_FW_EXT_CLK_CONTROL = 0, WIL_PLATFORM_FEATURE_TRIPLE_MSI = 1, Loading @@ -52,6 +57,7 @@ struct wil_platform_ops { int (*notify)(void *handle, enum wil_platform_event evt); int (*get_capa)(void *handle); void (*set_features)(void *handle, int features); int (*pci_linkdown_recovery)(void *handle); }; /** Loading @@ -63,10 +69,13 @@ struct wil_platform_ops { * @fw_recovery: start a firmware recovery process. Called as * part of a crash recovery process which may include other * related platform subsystems. * @notify: get notifications from the Platform driver, such as * pci linkdown */ struct wil_platform_rops { int (*ramdump)(void *wil_handle, void *buf, uint32_t size); int (*fw_recovery)(void *wil_handle); int (*notify)(void *wil_handle, enum wil_platform_notif notif); }; /** Loading Loading
drivers/net/wireless/ath/wil6210/main.c +22 −10 Original line number Diff line number Diff line Loading @@ -536,23 +536,16 @@ bool wil_is_recovery_blocked(struct wil6210_priv *wil) return no_fw_recovery && (wil->recovery_state == fw_recovery_pending); } static void wil_fw_error_worker(struct work_struct *work) void wil_fw_recovery(struct wil6210_priv *wil) { struct wil6210_priv *wil = container_of(work, struct wil6210_priv, fw_error_worker); struct net_device *ndev = wil->main_ndev; struct wireless_dev *wdev; wil_dbg_misc(wil, "fw error worker\n"); if (!ndev || !(ndev->flags & IFF_UP)) { wil_info(wil, "No recovery - interface is down\n"); return; } wil_dbg_misc(wil, "fw recovery\n"); wdev = ndev->ieee80211_ptr; /* increment @recovery_count if less then WIL6210_FW_RECOVERY_TO /* increment @recovery_count if less than WIL6210_FW_RECOVERY_TO * passed since last recovery attempt */ if (time_is_after_jiffies(wil->last_fw_recovery + Loading Loading @@ -612,6 +605,22 @@ static void wil_fw_error_worker(struct work_struct *work) rtnl_unlock(); } static void wil_fw_error_worker(struct work_struct *work) { struct wil6210_priv *wil = container_of(work, struct wil6210_priv, fw_error_worker); struct net_device *ndev = wil->main_ndev; wil_dbg_misc(wil, "fw error worker\n"); if (!ndev || !(ndev->flags & IFF_UP)) { wil_info(wil, "No recovery - interface is down\n"); return; } wil_fw_recovery(wil); } static int wil_find_free_ring(struct wil6210_priv *wil) { int i; Loading Loading @@ -724,6 +733,8 @@ int wil_priv_init(struct wil6210_priv *wil) INIT_WORK(&wil->wmi_event_worker, wmi_event_worker); INIT_WORK(&wil->fw_error_worker, wil_fw_error_worker); INIT_WORK(&wil->pci_linkdown_recovery_worker, wil_pci_linkdown_recovery_worker); INIT_LIST_HEAD(&wil->pending_wmi_ev); spin_lock_init(&wil->wmi_ev_lock); Loading Loading @@ -839,6 +850,7 @@ void wil_priv_deinit(struct wil6210_priv *wil) wil_set_recovery_state(wil, fw_recovery_idle); cancel_work_sync(&wil->fw_error_worker); cancel_work_sync(&wil->pci_linkdown_recovery_worker); wmi_event_flush(wil); destroy_workqueue(wil->wq_service); destroy_workqueue(wil->wmi_wq); Loading
drivers/net/wireless/ath/wil6210/pcie_bus.c +109 −1 Original line number Diff line number Diff line /* * Copyright (c) 2012-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018, The Linux Foundation. All rights reserved. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above Loading Loading @@ -298,6 +298,108 @@ static int wil_platform_rop_fw_recovery(void *wil_handle) return 0; } void wil_pci_linkdown_recovery_worker(struct work_struct *work) { struct wil6210_priv *wil = container_of(work, struct wil6210_priv, pci_linkdown_recovery_worker); int rc, i; struct wil6210_vif *vif; struct net_device *ndev = wil->main_ndev; wil_dbg_misc(wil, "starting pci_linkdown recovery\n"); rtnl_lock(); mutex_lock(&wil->mutex); down_write(&wil->mem_lock); clear_bit(wil_status_fwready, wil->status); set_bit(wil_status_pci_linkdown, wil->status); set_bit(wil_status_resetting, wil->status); up_write(&wil->mem_lock); if (test_and_clear_bit(wil_status_napi_en, wil->status)) { napi_disable(&wil->napi_rx); napi_disable(&wil->napi_tx); } mutex_unlock(&wil->mutex); rtnl_unlock(); mutex_lock(&wil->mutex); mutex_lock(&wil->vif_mutex); wil_ftm_stop_operations(wil); wil_p2p_stop_radio_operations(wil); wil_abort_scan_all_vifs(wil, false); mutex_unlock(&wil->vif_mutex); for (i = 0; i < wil->max_vifs; i++) { vif = wil->vifs[i]; if (vif) { cancel_work_sync(&vif->disconnect_worker); wil6210_disconnect(vif, NULL, WLAN_REASON_DEAUTH_LEAVING); } } wmi_event_flush(wil); flush_workqueue(wil->wq_service); flush_workqueue(wil->wmi_wq); /* Recover PCIe */ if (wil->platform_ops.pci_linkdown_recovery) { rc = wil->platform_ops.pci_linkdown_recovery( wil->platform_handle); if (rc) { wil_err(wil, "platform device failed to recover from pci linkdown (%d)\n", rc); mutex_unlock(&wil->mutex); goto out; } } else { wil_err(wil, "platform device doesn't support pci_linkdown recovery\n"); mutex_unlock(&wil->mutex); goto out; } if (!ndev || !(ndev->flags & IFF_UP)) { wil_reset(wil, false); mutex_unlock(&wil->mutex); } else { mutex_unlock(&wil->mutex); wil->recovery_state = fw_recovery_pending; wil_fw_recovery(wil); } out: return; } static int wil_platform_rop_notify(void *wil_handle, enum wil_platform_notif notif) { struct wil6210_priv *wil = wil_handle; if (!wil) return -EINVAL; switch (notif) { case WIL_PLATFORM_NOTIF_PCI_LINKDOWN: wil_info(wil, "received WIL_PLATFORM_NOTIF_PCI_LINKDOWN\n"); clear_bit(wil_status_fwready, wil->status); set_bit(wil_status_resetting, wil->status); set_bit(wil_status_pci_linkdown, wil->status); schedule_work(&wil->pci_linkdown_recovery_worker); break; default: break; } return 0; } static void wil_platform_ops_uninit(struct wil6210_priv *wil) { if (wil->platform_ops.uninit) Loading @@ -313,6 +415,7 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) const struct wil_platform_rops rops = { .ramdump = wil_platform_rop_ramdump, .fw_recovery = wil_platform_rop_fw_recovery, .notify = wil_platform_rop_notify, }; u32 bar_size = pci_resource_len(pdev, 0); int dma_addr_size[] = {64, 48, 40, 32}; /* keep descending order */ Loading Loading @@ -560,6 +663,11 @@ static int wil6210_resume(struct device *dev, bool is_runtime) struct wil6210_priv *wil = pci_get_drvdata(pdev); bool keep_radio_on, active_ifaces; if (test_bit(wil_status_pci_linkdown, wil->status)) { wil_dbg_pm(wil, "ignore resume during pci linkdown\n"); return 0; } wil_dbg_pm(wil, "resume: %s\n", is_runtime ? "runtime" : "system"); mutex_lock(&wil->vif_mutex); Loading
drivers/net/wireless/ath/wil6210/pm.c +6 −0 Original line number Diff line number Diff line Loading @@ -101,6 +101,12 @@ int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime) goto out; } if (test_bit(wil_status_pci_linkdown, wil->status)) { wil_dbg_pm(wil, "Delay suspend during pci linkdown\n"); rc = -EBUSY; goto out; } mutex_lock(&wil->vif_mutex); active_ifaces = wil_has_active_ifaces(wil, true, false); mutex_unlock(&wil->vif_mutex); Loading
drivers/net/wireless/ath/wil6210/wil6210.h +6 −0 Original line number Diff line number Diff line Loading @@ -661,6 +661,7 @@ enum { /* for wil6210_priv.status */ wil_status_suspending, /* suspend in progress */ wil_status_suspended, /* suspend completed, device is suspended */ wil_status_resuming, /* resume in progress */ wil_status_pci_linkdown, /* pci linkdown occurred */ wil_status_last /* keep last */ }; Loading Loading @@ -1074,6 +1075,8 @@ struct wil6210_priv { u32 max_ampdu_size; struct wil_fw_stats_global fw_stats_global; struct work_struct pci_linkdown_recovery_worker; }; #define wil_to_wiphy(i) (i->wiphy) Loading Loading @@ -1365,6 +1368,9 @@ void wil_disconnect_worker(struct work_struct *work); void wil_init_txrx_ops(struct wil6210_priv *wil); void wil_fw_recovery(struct wil6210_priv *wil); void wil_pci_linkdown_recovery_worker(struct work_struct *work); /* TX API */ int wil_ring_init_tx(struct wil6210_vif *vif, int cid); int wil_vring_init_bcast(struct wil6210_vif *vif, int id, int size); Loading
drivers/net/wireless/ath/wil6210/wil_platform.h +9 −0 Original line number Diff line number Diff line /* * Copyright (c) 2014-2017 Qualcomm Atheros, Inc. * Copyright (c) 2019, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above Loading Loading @@ -27,6 +28,10 @@ enum wil_platform_event { WIL_PLATFORM_EVT_POST_SUSPEND = 4, }; enum wil_platform_notif { WIL_PLATFORM_NOTIF_PCI_LINKDOWN = 0, }; enum wil_platform_features { WIL_PLATFORM_FEATURE_FW_EXT_CLK_CONTROL = 0, WIL_PLATFORM_FEATURE_TRIPLE_MSI = 1, Loading @@ -52,6 +57,7 @@ struct wil_platform_ops { int (*notify)(void *handle, enum wil_platform_event evt); int (*get_capa)(void *handle); void (*set_features)(void *handle, int features); int (*pci_linkdown_recovery)(void *handle); }; /** Loading @@ -63,10 +69,13 @@ struct wil_platform_ops { * @fw_recovery: start a firmware recovery process. Called as * part of a crash recovery process which may include other * related platform subsystems. * @notify: get notifications from the Platform driver, such as * pci linkdown */ struct wil_platform_rops { int (*ramdump)(void *wil_handle, void *buf, uint32_t size); int (*fw_recovery)(void *wil_handle); int (*notify)(void *wil_handle, enum wil_platform_notif notif); }; /** Loading