Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > fc11cd6e1c513a17304da94a5390f3cd > files > 2982

kernel-2.6.18-194.11.1.el5.src.rpm

From: AMEET M. PARANJAPE <aparanja@redhat.com>
Date: Fri, 5 Jun 2009 10:35:00 -0400
Subject: [ppc64] resolves issues with pcie-save-restore-state
Message-id: 20090605143149.5066.91565.sendpatchset@squad5-lp1.lab.bos.redhat.com
O-Subject: [PATCH RHEL5.4 BZ504198] Resolves issues with pcie-save-restore-state
Bugzilla: 504198
RH-Acked-by: David Howells <dhowells@redhat.com>

RHBZ#:
======
https://bugzilla.redhat.com/show_bug.cgi?id=504198

Description:
===========
The patch fixes issues introduced by this patch in RH BZ 493152:

[RHEL5.4 PATCH 15/17] BZ493152: Backport: PCI: Restore PCI Express capability
registers after PM event

1)  Patch added calls to new pci_save_pcie_state()) & pci_restore_pcie_state()
to pci_save_state()/pci_restore_state() but did not remove the calls added in
RHEL5.3 to support EEH, save_pcie_reg() and restore_pcie_reg();

2)  In function pci_save_pcie_state(), the value for
save_state->cap_nr = PCI_CAP_ID_EXP;  must be set prior to call to
pci_add_saved_cap(dev, save_state);

3) In function pci_save_pcie_state(), save_state buffer should be allocated
once and saved in saved_cap for subsequent uses.
For example:
  save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP);
  if (!save_state) {
       save_state = kzalloc(sizeof(struct pci_cap_saved_state) + sizeo(u16),
                                     GFP_KERNEL);
        if (!save_state) {
             printk(KERN_ERR "Out of memory in pci_save_pcie_state\n");
             return -ENOMEM;
         }
         save_state->cap_nr = PCI_CAP_ID_EXP;
         pci_add_saved_cap(dev, save_state);

4) In function pci_restore_pcie_state(), saved_cap should not be removed, this
is what breaks EEH recovery on second EEH error.
EEH recovery depends upon state saved during adapter initialization to be
restored after PCI slot reset.

RHEL Version Found:
================
RHEL 5.4

kABI Status:
============
No symbols were harmed.

Brew:
=====
Built on all platforms.
http://brewweb.devel.redhat.com/brew/taskinfo?taskID=1827916

Upstream Status:
================
The recent 5.4 patch:

[RHEL5.4 PATCH 15/17] BZ493152: Backport: PCI: Restore PCI Express capability
registers after PM event

looks similar to commit fb56a5a23bfecd9cac9187164a9d5f22d287c48b9.  In the
upstream code save_pcie_reg() and restore_pcie_reg() are no longer needed.

The save_state->cap_nr line comes from commit ID
ec0a3a27fbb5792980b8c3ce4a93bc2ee93d0b35.  Without it, the saved state cannot
be found in pci_restore_pcie_state().

Removal of the lines that delete the saved state after a restore comes from
commit ID 9f35575dfc172f0a93fb464761883c8f49599b7a.

Test Status:
============
Result of second eeh error injection on Emulex PCIe adapter before patch:
lpfc 0003:01:00.1: 3:0438 Adapter failed to init, chipset, status reg
xffffffff, FW Data: A8 xffffffff AC xffffffff
lpfc 0003:01:00.1: 3:0438 Adapter failed to init, chipset, status reg
xffffffff, FW Data: A8 xffffffff AC xffffffff

With patch applied EEH recovers as expected from 5 EEH error injections.
===============================================================
Ameet Paranjape 978-392-3903 ext 23903
IBM on-site partner

Proposed Patch:
===============

diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c
index 778d2b5..34b87a6 100644
--- a/arch/powerpc/platforms/pseries/eeh.c
+++ b/arch/powerpc/platforms/pseries/eeh.c
@@ -128,59 +128,6 @@ static unsigned long slot_resets;
 /* --------------------------------------------------------------- */
 /* Below lies the EEH event infrastructure */
 
-int save_pcie_reg(struct pci_dev *dev)
-{
-	int pos, i = 0;
-	struct pci_cap_saved_state *save_state;
-	u16 *cap;
-
-	pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
-	if (pos <= 0)
-		return 0;
-
-	save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP);
-	if (save_state)
-		return 0;
-
-	save_state = kzalloc(sizeof(*save_state) + sizeof(u16) * 4, GFP_KERNEL);
-	if (!save_state) {
-		dev_err(&dev->dev, "Out of memory in save_pcie_reg\n");
-		return -ENOMEM;
-	}
-
-	cap = (u16 *)&save_state->data[0];
-
-	pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &cap[i++]);
-	pci_read_config_word(dev, pos + PCI_EXP_LNKCTL, &cap[i++]);
-	pci_read_config_word(dev, pos + PCI_EXP_SLTCTL, &cap[i++]);
-	pci_read_config_word(dev, pos + PCI_EXP_RTCTL, &cap[i++]);
-	save_state->cap_nr = PCI_CAP_ID_EXP;
-	pci_add_saved_cap(dev, save_state);
-
-	return 0;
-}
-
-void restore_pcie_reg(struct pci_dev *dev)
-{
-	int i = 0, pos;
-	struct pci_cap_saved_state *save_state;
-	u16 *cap;
-
-	save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP);
-	pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
-	if (!save_state || pos <= 0)
-		return;
-	cap = (u16 *)&save_state->data[0];
-
-	pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, cap[i++]);
-	pci_write_config_word(dev, pos + PCI_EXP_LNKCTL, cap[i++]);
-	pci_write_config_word(dev, pos + PCI_EXP_SLTCTL, cap[i++]);
-	pci_write_config_word(dev, pos + PCI_EXP_RTCTL, cap[i++]);
-}
-
-EXPORT_SYMBOL_GPL(save_pcie_reg);
-EXPORT_SYMBOL_GPL(restore_pcie_reg);
-
 static void rtas_slot_error_detail(struct pci_dn *pdn, int severity,
                                    char *driver_log, size_t loglen)
 {
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index a0e35fa..9bc4ffb 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -567,10 +567,15 @@ static int pci_save_pcie_state(struct pci_dev *dev)
 	if (pos <= 0)
 		return 0;
 
-	save_state = kzalloc(sizeof(*save_state) + sizeof(u16) * 7, GFP_KERNEL);
+	save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP);
 	if (!save_state) {
-		dev_err(&dev->dev, "Out of memory in pci_save_pcie_state\n");
-		return -ENOMEM;
+		save_state = kzalloc(sizeof(*save_state) + sizeof(u16) * 7, GFP_KERNEL);
+		if (!save_state) {
+			printk(KERN_ERR "Out of memory in pci_save_pcie_state\n");
+			return -ENOMEM;
+		}
+		save_state->cap_nr = PCI_CAP_ID_EXP;
+		pci_add_saved_cap(dev, save_state);
 	}
 	cap = (u16 *)&save_state->data[0];
 
@@ -604,8 +609,6 @@ static void pci_restore_pcie_state(struct pci_dev *dev)
 	pci_write_config_word(dev, pos + PCI_EXP_DEVCTL2, cap[i++]);
 	pci_write_config_word(dev, pos + PCI_EXP_LNKCTL2, cap[i++]);
 	pci_write_config_word(dev, pos + PCI_EXP_SLTCTL2, cap[i++]);
-	pci_remove_saved_cap(save_state);
-	kfree(save_state);
 }
 
 /**
@@ -617,7 +620,6 @@ pci_save_state(struct pci_dev *dev)
 {
 	int i;
 
-	save_pcie_reg(dev);
 	/* XXX: 100% dword access ok here? */
 	for (i = 0; i < 16; i++)
 		pci_read_config_dword(dev, i * 4,&dev->saved_config_space[i]);
@@ -658,7 +660,6 @@ pci_restore_state(struct pci_dev *dev)
 				dev->saved_config_space[i]);
 		}
 	}
-	restore_pcie_reg(dev);
 	pci_restore_msi_state(dev);
 	pci_restore_msix_state(dev);
 	pci_restore_iov_state(dev);