From: Gavin Shan <shangw@linux.vnet.ibm.com>
To: linuxppc-dev@lists.ozlabs.org
Cc: Gavin Shan <shangw@linux.vnet.ibm.com>
Subject: [PATCH 2/2] powerpc/eeh: Check PCIe link in pcibios_set_pcie_reset_state()
Date: Mon, 3 Mar 2014 11:26:32 +0800 [thread overview]
Message-ID: <1393817192-14271-2-git-send-email-shangw@linux.vnet.ibm.com> (raw)
In-Reply-To: <1393817192-14271-1-git-send-email-shangw@linux.vnet.ibm.com>
After PE reset in pcibios_set_pcie_reset_state(), the PCIe link
might be not ready after settle time of PE primary bus. The
subsequent access to PCI config and MMIO of the affected domain
would cause more problems (e.g. unexpected frozen PE).
The patch checks the PCIe link in pcibios_set_pcie_reset_state()
to make sure all PCIe links are up after PE reset so that to
avoid unexpected problems.
Signed-off-by: Gavin Shan <shangw@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/eeh.h | 1 +
arch/powerpc/kernel/eeh.c | 29 +++++++++++++++++++++++++++++
arch/powerpc/kernel/eeh_pe.c | 21 +++++++++++++--------
3 files changed, 43 insertions(+), 8 deletions(-)
diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h
index d4dd41f..e96ed32 100644
--- a/arch/powerpc/include/asm/eeh.h
+++ b/arch/powerpc/include/asm/eeh.h
@@ -231,6 +231,7 @@ void *eeh_pe_traverse(struct eeh_pe *root,
eeh_traverse_func fn, void *flag);
void *eeh_pe_dev_traverse(struct eeh_pe *root,
eeh_traverse_func fn, void *flag);
+void eeh_bridge_check_link(struct eeh_dev *edev);
void eeh_pe_restore_bars(struct eeh_pe *pe);
struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe);
diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c
index 251e370..ba2dd2d 100644
--- a/arch/powerpc/kernel/eeh.c
+++ b/arch/powerpc/kernel/eeh.c
@@ -532,6 +532,14 @@ int eeh_pci_enable(struct eeh_pe *pe, int function)
return rc;
}
+static void *eeh_dev_check_link(void *data, void *flag)
+{
+ struct eeh_dev *edev = data;
+
+ eeh_bridge_check_link(edev);
+ return NULL;
+}
+
/**
* pcibios_set_pcie_slot_reset - Set PCI-E reset state
* @dev: pci device struct
@@ -544,6 +552,7 @@ int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state stat
{
struct eeh_dev *edev = pci_dev_to_eeh_dev(dev);
struct eeh_pe *pe = edev->pe;
+ struct pci_bus *bus;
if (!pe) {
pr_err("%s: No PE found on PCI device %s\n",
@@ -551,10 +560,30 @@ int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state stat
return -EINVAL;
}
+ bus = eeh_pe_bus_get(pe);
+ if (!bus) {
+ pr_err("%s: No PE primary bus found for PCI dev %s\n",
+ __func__, pci_name(dev));
+ return -EINVAL;
+ }
+
switch (state) {
case pcie_deassert_reset:
eeh_ops->reset(pe, EEH_RESET_DEACTIVATE);
msleep(EEH_PE_RESET_HOLD_TIME);
+
+ /*
+ * After PE reset, the PCIe link is probably
+ * not ready after settle period. We're checking
+ * all PCIe downstream port of the affected PE
+ * ensure that.
+ */
+ if (bus->self) {
+ edev = pci_dev_to_eeh_dev(bus->self);
+ eeh_bridge_check_link(edev);
+ }
+ eeh_pe_dev_traverse(pe, eeh_dev_check_link, NULL);
+
break;
case pcie_hot_reset:
eeh_ops->reset(pe, EEH_RESET_HOT);
diff --git a/arch/powerpc/kernel/eeh_pe.c b/arch/powerpc/kernel/eeh_pe.c
index f0c353f..a49f9dc 100644
--- a/arch/powerpc/kernel/eeh_pe.c
+++ b/arch/powerpc/kernel/eeh_pe.c
@@ -567,6 +567,9 @@ void eeh_pe_state_clear(struct eeh_pe *pe, int state)
}
/*
+ * eeh_bridge_check_link - Check PCI link is up or down
+ * @edev: EEH device
+ *
* Some PCI bridges (e.g. PLX bridges) have primary/secondary
* buses assigned explicitly by firmware, and we probably have
* lost that after reset. So we have to delay the check until
@@ -577,18 +580,20 @@ void eeh_pe_state_clear(struct eeh_pe *pe, int state)
* blocked on normal path during the stage. So we need utilize
* eeh operations, which is always permitted.
*/
-static void eeh_bridge_check_link(struct eeh_dev *edev,
- struct device_node *dn)
+void eeh_bridge_check_link(struct eeh_dev *edev)
{
+ struct device_node *dn;
int cap;
uint32_t val;
int timeout = 0;
- /*
- * We only check root port and downstream ports of
- * PCIe switches
- */
- if (!(edev->mode & (EEH_DEV_ROOT_PORT | EEH_DEV_DS_PORT)))
+ /* Only for root port and downstream ports */
+ if (!edev || !(edev->mode & (EEH_DEV_ROOT_PORT | EEH_DEV_DS_PORT)))
+ return;
+
+ /* Device node */
+ dn = eeh_dev_to_of_node(edev);
+ if (!dn)
return;
pr_debug("%s: Check PCIe link for %04x:%02x:%02x.%01x ...\n",
@@ -678,7 +683,7 @@ static void eeh_restore_bridge_bars(struct eeh_dev *edev,
eeh_ops->write_config(dn, PCI_COMMAND, 4, edev->config_space[1]);
/* Check the PCIe link is ready */
- eeh_bridge_check_link(edev, dn);
+ eeh_bridge_check_link(edev);
}
static void eeh_restore_device_bars(struct eeh_dev *edev,
--
1.7.10.4
prev parent reply other threads:[~2014-03-03 3:26 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-03-03 3:26 [PATCH 1/2] powerpc/eeh: More reliability of PCI dev reset Gavin Shan
2014-03-03 3:26 ` Gavin Shan [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1393817192-14271-2-git-send-email-shangw@linux.vnet.ibm.com \
--to=shangw@linux.vnet.ibm.com \
--cc=linuxppc-dev@lists.ozlabs.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).