On Tue, Dec 29, 2020 at 09:43:48AM +0100, Loic Poulain wrote: > In AER capable root complex, errors are reported to the host which > can then act accordingly and perform PCI recovering procedure. > > This patch enables error reporting and implements error_detected, > slot_reset and resume callbacks. > > Signed-off-by: Loic Poulain <loic.poulain@xxxxxxxxxx> > Reviewed-by Hemant Kumar <hemantk@xxxxxxxxxxxxxx> > --- > drivers/bus/mhi/pci_generic.c | 50 +++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 50 insertions(+) > > diff --git a/drivers/bus/mhi/pci_generic.c b/drivers/bus/mhi/pci_generic.c > index 3297d95..9fe1e30 100644 > --- a/drivers/bus/mhi/pci_generic.c > +++ b/drivers/bus/mhi/pci_generic.c > @@ -8,6 +8,7 @@ > * Copyright (C) 2020 Linaro Ltd <loic.poulain@xxxxxxxxxx> > */ > > +#include <linux/aer.h> > #include <linux/delay.h> > #include <linux/device.h> > #include <linux/mhi.h> > @@ -405,6 +406,8 @@ static int mhi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) > pci_save_state(pdev); > mhi_pdev->pci_state = pci_store_saved_state(pdev); > > + pci_enable_pcie_error_reporting(pdev); > + > err = mhi_register_controller(mhi_cntrl, mhi_cntrl_config); > if (err) > return err; > @@ -501,7 +504,54 @@ static void mhi_pci_reset_done(struct pci_dev *pdev) > set_bit(MHI_PCI_DEV_STARTED, &mhi_pdev->status); > } > > +static pci_ers_result_t mhi_pci_error_detected(struct pci_dev *pdev, > + pci_channel_state_t state) > +{ > + struct mhi_pci_device *mhi_pdev = pci_get_drvdata(pdev); > + struct mhi_controller *mhi_cntrl = &mhi_pdev->mhi_cntrl; > + > + dev_err(&pdev->dev, "PCI error detected, state = %u\n", state); > + > + if (state == pci_channel_io_perm_failure) > + return PCI_ERS_RESULT_DISCONNECT; > + > + /* Clean up MHI state */ > + if (test_and_clear_bit(MHI_PCI_DEV_STARTED, &mhi_pdev->status)) { > + mhi_power_down(mhi_cntrl, false); > + mhi_unprepare_after_power_down(mhi_cntrl); > + } else { > + /* Nothing to do */ > + return PCI_ERS_RESULT_RECOVERED; > + } > + > + pci_disable_device(pdev); > + > + return PCI_ERS_RESULT_NEED_RESET; > +} > + > +static pci_ers_result_t mhi_pci_slot_reset(struct pci_dev *pdev) > +{ > + if (pci_enable_device(pdev)) { > + dev_err(&pdev->dev, "Cannot re-enable PCI device after reset.\n"); > + return PCI_ERS_RESULT_DISCONNECT; > + } > + This callback will be called after PCI slot reset, so we should also be resetting the device after enabling it. Thanks, Mani > + return PCI_ERS_RESULT_RECOVERED; > +} > + > +static void mhi_pci_io_resume(struct pci_dev *pdev) > +{ > + struct mhi_pci_device *mhi_pdev = pci_get_drvdata(pdev); > + > + dev_err(&pdev->dev, "PCI slot reset done\n"); > + > + queue_work(system_long_wq, &mhi_pdev->recovery_work); > +} > + > static const struct pci_error_handlers mhi_pci_err_handler = { > + .error_detected = mhi_pci_error_detected, > + .slot_reset = mhi_pci_slot_reset, > + .resume = mhi_pci_io_resume, > .reset_prepare = mhi_pci_reset_prepare, > .reset_done = mhi_pci_reset_done, > }; > -- > 2.7.4 >