#include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
+#include <linux/module.h>
 #include <linux/pci.h>
 #include <asm/eeh.h>
 #include <asm/eeh_event.h>
        return "";
 }
 
+/**
+ * eeh_pcid_get - Get the PCI device driver
+ * @pdev: PCI device
+ *
+ * The function is used to retrieve the PCI device driver for
+ * the indicated PCI device. Besides, we will increase the reference
+ * of the PCI device driver to prevent that being unloaded on
+ * the fly. Otherwise, kernel crash would be seen.
+ */
+static inline struct pci_driver *eeh_pcid_get(struct pci_dev *pdev)
+{
+       if (!pdev || !pdev->driver)
+               return NULL;
+
+       if (!try_module_get(pdev->driver->driver.owner))
+               return NULL;
+
+       return pdev->driver;
+}
+
+/**
+ * eeh_pcid_put - Dereference on the PCI device driver
+ * @pdev: PCI device
+ *
+ * The function is called to do dereference on the PCI device
+ * driver of the indicated PCI device.
+ */
+static inline void eeh_pcid_put(struct pci_dev *pdev)
+{
+       if (!pdev || !pdev->driver)
+               return;
+
+       module_put(pdev->driver->driver.owner);
+}
+
 #if 0
 static void print_device_node_tree(struct pci_dn *pdn, int dent)
 {
 static int eeh_report_error(struct pci_dev *dev, void *userdata)
 {
        enum pci_ers_result rc, *res = userdata;
-       struct pci_driver *driver = dev->driver;
+       struct pci_driver *driver;
 
        dev->error_state = pci_channel_io_frozen;
 
-       if (!driver)
-               return 0;
+       driver = eeh_pcid_get(dev);
+       if (!driver) return 0;
 
        eeh_disable_irq(dev);
 
        if (!driver->err_handler ||
-           !driver->err_handler->error_detected)
+           !driver->err_handler->error_detected) {
+               eeh_pcid_put(dev);
                return 0;
+       }
 
        rc = driver->err_handler->error_detected (dev, pci_channel_io_frozen);
 
        if (rc == PCI_ERS_RESULT_NEED_RESET) *res = rc;
        if (*res == PCI_ERS_RESULT_NONE) *res = rc;
 
+       eeh_pcid_put(dev);
        return 0;
 }
 
 static int eeh_report_mmio_enabled(struct pci_dev *dev, void *userdata)
 {
        enum pci_ers_result rc, *res = userdata;
-       struct pci_driver *driver = dev->driver;
+       struct pci_driver *driver;
 
-       if (!driver ||
-           !driver->err_handler ||
-           !driver->err_handler->mmio_enabled)
+       driver = eeh_pcid_get(dev);
+       if (!driver) return 0;
+       if (!driver->err_handler ||
+           !driver->err_handler->mmio_enabled) {
+               eeh_pcid_put(dev);
                return 0;
+       }
 
        rc = driver->err_handler->mmio_enabled (dev);
 
        if (rc == PCI_ERS_RESULT_NEED_RESET) *res = rc;
        if (*res == PCI_ERS_RESULT_NONE) *res = rc;
 
+       eeh_pcid_put(dev);
        return 0;
 }
 
 static int eeh_report_reset(struct pci_dev *dev, void *userdata)
 {
        enum pci_ers_result rc, *res = userdata;
-       struct pci_driver *driver = dev->driver;
-
-       if (!driver)
-               return 0;
+       struct pci_driver *driver;
 
        dev->error_state = pci_channel_io_normal;
 
+       driver = eeh_pcid_get(dev);
+       if (!driver) return 0;
+
        eeh_enable_irq(dev);
 
        if (!driver->err_handler ||
-           !driver->err_handler->slot_reset)
+           !driver->err_handler->slot_reset) {
+               eeh_pcid_put(dev);
                return 0;
+       }
 
        rc = driver->err_handler->slot_reset(dev);
        if ((*res == PCI_ERS_RESULT_NONE) ||
        if (*res == PCI_ERS_RESULT_DISCONNECT &&
             rc == PCI_ERS_RESULT_NEED_RESET) *res = rc;
 
+       eeh_pcid_put(dev);
        return 0;
 }
 
 
 static int eeh_report_resume(struct pci_dev *dev, void *userdata)
 {
-       struct pci_driver *driver = dev->driver;
+       struct pci_driver *driver;
 
        dev->error_state = pci_channel_io_normal;
 
-       if (!driver)
-               return 0;
+       driver = eeh_pcid_get(dev);
+       if (!driver) return 0;
 
        eeh_enable_irq(dev);
 
        if (!driver->err_handler ||
-           !driver->err_handler->resume)
+           !driver->err_handler->resume) {
+               eeh_pcid_put(dev);
                return 0;
+       }
 
        driver->err_handler->resume(dev);
 
+       eeh_pcid_put(dev);
        return 0;
 }
 
 
 static int eeh_report_failure(struct pci_dev *dev, void *userdata)
 {
-       struct pci_driver *driver = dev->driver;
+       struct pci_driver *driver;
 
        dev->error_state = pci_channel_io_perm_failure;
 
-       if (!driver)
-               return 0;
+       driver = eeh_pcid_get(dev);
+       if (!driver) return 0;
 
        eeh_disable_irq(dev);
 
        if (!driver->err_handler ||
-           !driver->err_handler->error_detected)
+           !driver->err_handler->error_detected) {
+               eeh_pcid_put(dev);
                return 0;
+       }
 
        driver->err_handler->error_detected(dev, pci_channel_io_perm_failure);
 
+       eeh_pcid_put(dev);
        return 0;
 }