Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 330335
b: refs/heads/master
c: feadf7c
h: refs/heads/master
i:
  330333: 7aeb990
  330331: 6f15251
  330327: d8c2bc1
  330319: 844cd0e
  330303: 90a4adf
v: v3
  • Loading branch information
Gavin Shan authored and Benjamin Herrenschmidt committed Sep 18, 2012
1 parent 0754ded commit c459cf0
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 22 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 8e9f69371536981a2a8c9ee4a49dbe3aa4946df4
refs/heads/master: feadf7c0a1a7c08c74bebb4a13b755f8c40e3bbc
91 changes: 70 additions & 21 deletions trunk/arch/powerpc/platforms/pseries/eeh_driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#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>
Expand All @@ -47,6 +48,41 @@ static inline const char *eeh_pcid_name(struct pci_dev *pdev)
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)
{
Expand Down Expand Up @@ -128,30 +164,32 @@ static void *eeh_report_error(void *data, void *userdata)
struct eeh_dev *edev = (struct eeh_dev *)data;
struct pci_dev *dev = eeh_dev_to_pci_dev(edev);
enum pci_ers_result rc, *res = userdata;
struct pci_driver *driver = dev->driver;
struct pci_driver *driver;

/* We might not have the associated PCI device,
* then we should continue for next one.
*/
if (!dev) return NULL;

dev->error_state = pci_channel_io_frozen;

if (!driver)
return NULL;
driver = eeh_pcid_get(dev);
if (!driver) return NULL;

eeh_disable_irq(dev);

if (!driver->err_handler ||
!driver->err_handler->error_detected)
!driver->err_handler->error_detected) {
eeh_pcid_put(dev);
return NULL;
}

rc = driver->err_handler->error_detected(dev, pci_channel_io_frozen);

/* A driver that needs a reset trumps all others */
if (rc == PCI_ERS_RESULT_NEED_RESET) *res = rc;
if (*res == PCI_ERS_RESULT_NONE) *res = rc;

eeh_pcid_put(dev);
return NULL;
}

Expand All @@ -171,19 +209,22 @@ static void *eeh_report_mmio_enabled(void *data, void *userdata)
enum pci_ers_result rc, *res = userdata;
struct pci_driver *driver;

if (!dev) return NULL;
driver = eeh_pcid_get(dev);
if (!driver) return NULL;

if (!(driver = dev->driver) ||
!driver->err_handler ||
!driver->err_handler->mmio_enabled)
if (!driver->err_handler ||
!driver->err_handler->mmio_enabled) {
eeh_pcid_put(dev);
return NULL;
}

rc = driver->err_handler->mmio_enabled(dev);

/* A driver that needs a reset trumps all others */
if (rc == PCI_ERS_RESULT_NEED_RESET) *res = rc;
if (*res == PCI_ERS_RESULT_NONE) *res = rc;

eeh_pcid_put(dev);
return NULL;
}

Expand All @@ -204,23 +245,27 @@ static void *eeh_report_reset(void *data, void *userdata)
enum pci_ers_result rc, *res = userdata;
struct pci_driver *driver;

if (!dev || !(driver = dev->driver))
return NULL;

if (!dev) return NULL;
dev->error_state = pci_channel_io_normal;

driver = eeh_pcid_get(dev);
if (!driver) return NULL;

eeh_enable_irq(dev);

if (!driver->err_handler ||
!driver->err_handler->slot_reset)
!driver->err_handler->slot_reset) {
eeh_pcid_put(dev);
return NULL;
}

rc = driver->err_handler->slot_reset(dev);
if ((*res == PCI_ERS_RESULT_NONE) ||
(*res == PCI_ERS_RESULT_RECOVERED)) *res = rc;
if (*res == PCI_ERS_RESULT_DISCONNECT &&
rc == PCI_ERS_RESULT_NEED_RESET) *res = rc;

eeh_pcid_put(dev);
return NULL;
}

Expand All @@ -240,20 +285,22 @@ static void *eeh_report_resume(void *data, void *userdata)
struct pci_driver *driver;

if (!dev) return NULL;

dev->error_state = pci_channel_io_normal;

if (!(driver = dev->driver))
return NULL;
driver = eeh_pcid_get(dev);
if (!driver) return NULL;

eeh_enable_irq(dev);

if (!driver->err_handler ||
!driver->err_handler->resume)
!driver->err_handler->resume) {
eeh_pcid_put(dev);
return NULL;
}

driver->err_handler->resume(dev);

eeh_pcid_put(dev);
return NULL;
}

Expand All @@ -272,20 +319,22 @@ static void *eeh_report_failure(void *data, void *userdata)
struct pci_driver *driver;

if (!dev) return NULL;

dev->error_state = pci_channel_io_perm_failure;

if (!(driver = dev->driver))
return NULL;
driver = eeh_pcid_get(dev);
if (!driver) return NULL;

eeh_disable_irq(dev);

if (!driver->err_handler ||
!driver->err_handler->error_detected)
!driver->err_handler->error_detected) {
eeh_pcid_put(dev);
return NULL;
}

driver->err_handler->error_detected(dev, pci_channel_io_perm_failure);

eeh_pcid_put(dev);
return NULL;
}

Expand Down

0 comments on commit c459cf0

Please sign in to comment.