Sometimes PCIe Advanced Error Reporting(AER), like bad TLP or
Data link protocol error, happens due to unstable pci signal or
no response from PCI host.
pcieport 0000:00:1c.0: AER: Uncorrected (Non-Fatal) error message received from 0000:01:00.0
rtw89_8852be 0000:01:00.0: PCIe Bus Error: severity=Uncorrected (Non-Fatal), type=Transaction Layer, (Requester ID)
rtw89_8852be 0000:01:00.0: device [10ec:b852] error status/mask=
00004000/
00400000
rtw89_8852be 0000:01:00.0: [14] CmpltTO (First)
rtw89_8852be 0000:01:00.0: SER catches error: 0x4000
pcieport 0000:00:1c.0: AER: device recovery successful
rtw89_8852be 0000:01:00.0: FW backtrace invalid key: 0xbb6c3214
ieee80211 phy0: Hardware restart was requested
Setup callback function to call SER function to reset driver to recover
from these states.
Signed-off-by: Chin-Yen Lee <timlee@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
Link: https://patch.msgid.link/20250523062711.27213-3-pkshih@realtek.com
SIMPLE_DEV_PM_OPS(rtw89_pm_ops, rtw89_pci_suspend, rtw89_pci_resume);
EXPORT_SYMBOL(rtw89_pm_ops);
+static pci_ers_result_t rtw89_pci_io_error_detected(struct pci_dev *pdev,
+ pci_channel_state_t state)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+
+ netif_device_detach(netdev);
+
+ return PCI_ERS_RESULT_NEED_RESET;
+}
+
+static pci_ers_result_t rtw89_pci_io_slot_reset(struct pci_dev *pdev)
+{
+ struct ieee80211_hw *hw = pci_get_drvdata(pdev);
+ struct rtw89_dev *rtwdev = hw->priv;
+
+ rtw89_ser_notify(rtwdev, MAC_AX_ERR_ASSERTION);
+
+ return PCI_ERS_RESULT_RECOVERED;
+}
+
+static void rtw89_pci_io_resume(struct pci_dev *pdev)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+
+ /* ack any pending wake events, disable PME */
+ pci_enable_wake(pdev, PCI_D0, 0);
+
+ netif_device_attach(netdev);
+}
+
+const struct pci_error_handlers rtw89_pci_err_handler = {
+ .error_detected = rtw89_pci_io_error_detected,
+ .slot_reset = rtw89_pci_io_slot_reset,
+ .resume = rtw89_pci_io_resume,
+};
+EXPORT_SYMBOL(rtw89_pci_err_handler);
+
const struct rtw89_pci_gen_def rtw89_pci_gen_ax = {
.isr_rdu = B_AX_RDU_INT,
.isr_halt_c2h = B_AX_HALT_C2H_INT_EN,
extern const struct dev_pm_ops rtw89_pm_ops;
extern const struct dev_pm_ops rtw89_pm_ops_be;
+extern const struct pci_error_handlers rtw89_pci_err_handler;
extern const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set;
extern const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set_v1;
extern const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set_be;
.probe = rtw89_pci_probe,
.remove = rtw89_pci_remove,
.driver.pm = &rtw89_pm_ops,
+ .err_handler = &rtw89_pci_err_handler,
};
module_pci_driver(rtw89_8851be_driver);
.probe = rtw89_pci_probe,
.remove = rtw89_pci_remove,
.driver.pm = &rtw89_pm_ops,
+ .err_handler = &rtw89_pci_err_handler,
};
module_pci_driver(rtw89_8852ae_driver);
.probe = rtw89_pci_probe,
.remove = rtw89_pci_remove,
.driver.pm = &rtw89_pm_ops,
+ .err_handler = &rtw89_pci_err_handler,
};
module_pci_driver(rtw89_8852be_driver);
.probe = rtw89_pci_probe,
.remove = rtw89_pci_remove,
.driver.pm = &rtw89_pm_ops,
+ .err_handler = &rtw89_pci_err_handler,
};
module_pci_driver(rtw89_8852bte_driver);
.probe = rtw89_pci_probe,
.remove = rtw89_pci_remove,
.driver.pm = &rtw89_pm_ops,
+ .err_handler = &rtw89_pci_err_handler,
};
module_pci_driver(rtw89_8852ce_driver);
.probe = rtw89_pci_probe,
.remove = rtw89_pci_remove,
.driver.pm = &rtw89_pm_ops_be,
+ .err_handler = &rtw89_pci_err_handler,
};
module_pci_driver(rtw89_8922ae_driver);