Skip to contentSkip to conversation

PCI Error Recovery patchset

PATCH In review Linas Vepstas 4 participants 27 messages Aug 23, 2005 – Aug 30, 2005 8 messages not in the archive

Subsystems (5)
lore
Share & tools
lore

A message that is not in the archive (sent off-list or not yet received): 20050823231817.829359000@bilge

#1 lore raw

cover PCI Error Recovery patchset

What follows is a set of patches to implement a PCI error recovery system. Some (newer) PCI controllers are able to detect and report PCI errors, these patches enable this hardware function.

-- the first patch adds documentation, explaining what this is and how
it works.
-- the next patch adds core infrastructure to include/linux/pci.h -- the next several patches add recovery support to three ethernet and
two scsi drivers.
-- the last patch is a big monster that implements the recovery
driver for the ppc64-specific pci controllers.

The first seven patches should apply cleanly to just about any recent kernel tree; the last patch requires GregKH's pci patchset, since some ppc64 functions changed recently.

--linas

A message that is not in the archive (sent off-list or not yet received): 20050823232140.337320000@bilge

#3 lore raw

PATCH 2/8 PCI Error Recovery: header file patch

Various PCI bus errors can be signaled by newer PCI controllers. Recovering from those errors requires an infrastructure to notify affected device drivers of the error, and a way of walking through a reset sequence. This patch adds a set of callbacks to be used by error recovery routines to notify device drivers of the various stages of recovery.

--

 include/linux/pci.h |   39 +++++++++++++++++++++++++++++++++++++++
 1 files changed, 39 insertions(+)
include/linux/pci.h +39 -0
Index: linux-2.6.13-rc6-git9/include/linux/pci.h
===================================================================
@@ -78,6 +78,16 @@
 #define PCI_UNKNOWN	((pci_power_t __force) 5)
 #define PCI_POWER_ERROR	((pci_power_t __force) -1)
 
+/** The pci_channel state describes connectivity between the CPU and
+ *  the pci device.  If some PCI bus between here and the pci device
+ *  has crashed or locked up, this info is reflected here.
+ */
+enum pci_channel_state {
+	pci_channel_io_normal = 0, /* I/O channel is in normal state */
+	pci_channel_io_frozen = 1, /* I/O to channel is blocked */
+	pci_channel_io_perm_failure, /* PCI card is dead */
+};
+
 /*
  * The pci_dev structure is used to describe PCI devices.
  */
@@ -110,6 +120,7 @@
 					   this is D0-D3, D0 being fully functional,
 					   and D3 being off. */
 
+	enum pci_channel_state error_state;  /* current connectivity state */
 	struct	device	dev;		/* Generic device interface */
 
 	/* device is compatible with these IDs */
@@ -231,6 +242,33 @@
 	unsigned int use_driver_data:1; /* pci_driver->driver_data is used */
 };
 
+/* ---------------------------------------------------------------- */
+/** PCI error recovery infrastructure.  If a PCI device driver provides
+ *  a set fof callbacks in struct pci_error_handlers, then that device driver
+ *  will be notified of PCI bus errors, and will be driven to recovery
+ *  when an error occurs.
+ */
+
+enum pcierr_result {
+	PCIERR_RESULT_NONE=0,        /* no result/none/not supported in device driver */
+	PCIERR_RESULT_CAN_RECOVER=1, /* Device driver can recover without slot reset */
+	PCIERR_RESULT_NEED_RESET,    /* Device driver wants slot to be reset. */
+	PCIERR_RESULT_DISCONNECT,    /* Device has completely failed, is unrecoverable */
+	PCIERR_RESULT_RECOVERED,     /* Device driver is fully recovered and operational */
+};
+
+/* PCI bus error event callbacks */
+struct pci_error_handlers
+{
+	int (*error_detected)(struct pci_dev *dev, enum pci_channel_state error);
+	int (*mmio_enabled)(struct pci_dev *dev); /* MMIO has been reanbled, but not DMA */
+	int (*link_reset)(struct pci_dev *dev);   /* PCI Express link has been reset */
+	int (*slot_reset)(struct pci_dev *dev);   /* PCI slot has been reset */
+	void (*resume)(struct pci_dev *dev);      /* Device driver may resume normal operations */
+};
+
+/* ---------------------------------------------------------------- */
+
 struct module;
 struct pci_driver {
 	struct list_head node;
@@ -244,6 +282,7 @@
 	int  (*enable_wake) (struct pci_dev *dev, pci_power_t state, int enable);   /* Enable wake event */
 	void (*shutdown) (struct pci_dev *dev);
 
+	struct pci_error_handlers *err_handler;
 	struct device_driver	driver;
 	struct pci_dynids dynids;
 };

--

A message that is not in the archive (sent off-list or not yet received): 20050823232140.520090000@bilge

#5 lore raw

PATCH 3/8 PCI Error Recovery: IPR SCSI device driver

Various PCI bus errors can be signaled by newer PCI controllers. This patch adds the PCI error recovery callbacks to the IPR SCSI device driver. The patch has been tested, and appears to work well.

--

 arch/ppc64/configs/pSeries_defconfig |    1 
 drivers/scsi/Kconfig                 |    8 +++
 drivers/scsi/ipr.c                   |   93 +++++++++++++++++++++++++++++++++++
 3 files changed, 102 insertions(+)
drivers/scsi/Kconfig +8 -0
Index: linux-2.6.13-rc6-git9/drivers/scsi/Kconfig
===================================================================
@@ -1065,6 +1065,14 @@
 	  If you enable this support, the iprdump daemon can be used
 	  to capture adapter failure analysis information.
 
+config SCSI_IPR_EEH_RECOVERY
+	bool "Enable PCI bus error recovery"
+	depends on SCSI_IPR && PPC_PSERIES
+	help
+		If you say Y here, the driver will be able to recover from
+		PCI bus errors on many PowerPC platforms. IBM pSeries users
+		should answer Y.
+
 config SCSI_ZALON
 	tristate "Zalon SCSI support"
 	depends on GSC && SCSI
drivers/scsi/ipr.c +93 -0

111 lines not on this page · raw message

arch/ppc64/configs/pSeries_defconfig +1 -0
Index: linux-2.6.13-rc6-git9/arch/ppc64/configs/pSeries_defconfig
===================================================================
@@ -476,6 +476,7 @@
 CONFIG_SCSI_IPR=y
 CONFIG_SCSI_IPR_TRACE=y
 CONFIG_SCSI_IPR_DUMP=y
+CONFIG_SCSI_IPR_EEH_RECOVERY=y
 # CONFIG_SCSI_QLOGIC_FC is not set
 # CONFIG_SCSI_QLOGIC_1280 is not set
 CONFIG_SCSI_QLA2XXX=y

--

A message that is not in the archive (sent off-list or not yet received): 20050823232140.903067000@bilge

#7 lore raw

PATCH 4/8 PCI Error Recovery: Symbios SCSI device driver

Various PCI bus errors can be signaled by newer PCI controllers. This patch adds the PCI error recovery callbacks to the Symbios SCSI device driver. The patch has been tested, and appears to work well.

--

 arch/ppc64/configs/pSeries_defconfig |    1 
 drivers/scsi/Kconfig                 |    8 ++
 drivers/scsi/sym53c8xx_2/sym_glue.c  |  124 +++++++++++++++++++++++++++++++++++
 drivers/scsi/sym53c8xx_2/sym_glue.h  |    4 +
 drivers/scsi/sym53c8xx_2/sym_hipd.c  |   16 ++++
 5 files changed, 153 insertions(+)
arch/ppc64/configs/pSeries_defconfig +1 -0
Index: linux-2.6.13-rc6-git9/arch/ppc64/configs/pSeries_defconfig
===================================================================
@@ -473,6 +473,7 @@
 CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
 CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
 # CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
+CONFIG_SCSI_SYM53C8XX_EEH_RECOVERY=y
 CONFIG_SCSI_IPR=y
 CONFIG_SCSI_IPR_TRACE=y
 CONFIG_SCSI_IPR_DUMP=y
drivers/scsi/Kconfig +8 -0
Index: linux-2.6.13-rc6-git9/drivers/scsi/Kconfig
===================================================================
@@ -1040,6 +1040,14 @@
 	  the card.  This is significantly slower then using memory
 	  mapped IO.  Most people should answer N.
 
+config SCSI_SYM53C8XX_EEH_RECOVERY
+	bool "Enable PCI bus error recovery"
+	depends on SCSI_SYM53C8XX_2 && PPC_PSERIES
+	help
+		If you say Y here, the driver will be able to recover from
+		PCI bus errors on many PowerPC platforms. IBM pSeries users
+		should answer Y.
+
 config SCSI_IPR
 	tristate "IBM Power Linux RAID adapter support"
 	depends on PCI && SCSI
drivers/scsi/sym53c8xx_2/sym_glue.c +124 -0

165 lines not on this page · raw message

drivers/scsi/sym53c8xx_2/sym_glue.h +4 -0
Index: linux-2.6.13-rc6-git9/drivers/scsi/sym53c8xx_2/sym_glue.h
===================================================================
@@ -181,6 +181,10 @@
 	char		chip_name[8];
 	struct pci_dev	*device;
 
+	/* pci bus i/o state; waiter for clearing of i/o state */
+	enum pci_channel_state io_state;
+	struct sym_eh_wait *io_reset_wait;
+
 	struct Scsi_Host *host;
 
 	void __iomem *	ioaddr;		/* MMIO kernel io address	*/
drivers/scsi/sym53c8xx_2/sym_hipd.c +16 -0
Index: linux-2.6.13-rc6-git9/drivers/scsi/sym53c8xx_2/sym_hipd.c
===================================================================
@@ -2806,6 +2806,7 @@
 	u_char	istat, istatc;
 	u_char	dstat;
 	u_short	sist;
+	u_int    icnt;
 
 	/*
 	 *  interrupt on the fly ?
@@ -2847,6 +2848,7 @@
 	sist	= 0;
 	dstat	= 0;
 	istatc	= istat;
+	icnt = 0;
 	do {
 		if (istatc & SIP)
 			sist  |= INW(np, nc_sist);
@@ -2854,6 +2856,20 @@
 			dstat |= INB(np, nc_dstat);
 		istatc = INB(np, nc_istat);
 		istat |= istatc;
+#ifdef CONFIG_SCSI_SYM53C8XX_EEH_RECOVERY
+		/* Prevent deadlock waiting on a condition that may never clear. */
+		/* XXX this is a temporary kludge; the correct to detect
+		 * a PCI bus error would be to use the io_check interfaces
+		 * proposed by Hidetoshi Seto <[email protected]>
+		 * Problem with polling like that is the state flag might not
+		 * be set.
+		 */
+		icnt ++;
+		if (100 < icnt) {
+			if (np->s.device->error_state != pci_channel_io_normal)
+				return;
+		}
+#endif /* CONFIG_SCSI_SYM53C8XX_EEH_RECOVERY */
 	} while (istatc & (SIP|DIP));
 
 	if (DEBUG_FLAGS & DEBUG_TINY)

--

A message that is not in the archive (sent off-list or not yet received): 20050823232141.286102000@bilge

#9 lore raw

PATCH 5/8 PCI Error Recovery: e100 network device driver

Various PCI bus errors can be signaled by newer PCI controllers. This patch adds the PCI error recovery callbacks to the intel ethernet e100 device driver. The patch has been tested, and appears to work well.

--

 arch/ppc64/configs/pSeries_defconfig |    1 
 drivers/net/Kconfig                  |    8 +++
 drivers/net/e100.c                   |   73 +++++++++++++++++++++++++++++++++++
 3 files changed, 82 insertions(+)
arch/ppc64/configs/pSeries_defconfig +1 -0
Index: linux-2.6.13-rc6-git9/arch/ppc64/configs/pSeries_defconfig
===================================================================
@@ -574,6 +574,7 @@
 # CONFIG_DGRS is not set
 # CONFIG_EEPRO100 is not set
 CONFIG_E100=y
+CONFIG_E100_EEH_RECOVERY=y
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
 # CONFIG_NE2K_PCI is not set
drivers/net/Kconfig +8 -0
Index: linux-2.6.13-rc6-git9/drivers/net/Kconfig
===================================================================
@@ -1392,6 +1392,14 @@
 	  <file:Documentation/networking/net-modules.txt>.  The module
 	  will be called e100.
 
+config E100_EEH_RECOVERY
+	bool "Enable PCI bus error recovery"
+	depends on E100 && PPC_PSERIES
+   help
+      If you say Y here, the driver will be able to recover from
+      PCI bus errors on many PowerPC platforms. IBM pSeries users
+      should answer Y.
+
 config LNE390
 	tristate "Mylex EISA LNE390A/B support (EXPERIMENTAL)"
 	depends on NET_PCI && EISA && EXPERIMENTAL
drivers/net/e100.c +73 -0

85 lines not on this page · raw message

--

A message that is not in the archive (sent off-list or not yet received): 20050823232141.925586000@bilge

#11 lore raw

PATCH 6/8 PCI Error Recovery: e1000 network device driver

Various PCI bus errors can be signaled by newer PCI controllers. This patch adds the PCI error recovery callbacks to the intel gigabit ethernet e1000 device driver. The patch has been tested, and appears to work well.

--

 arch/ppc64/configs/pSeries_defconfig |    1 
 drivers/net/Kconfig                  |    8 ++
 drivers/net/e1000/e1000_main.c       |  103 ++++++++++++++++++++++++++++++++++-
 3 files changed, 111 insertions(+), 1 deletion(-)
arch/ppc64/configs/pSeries_defconfig +1 -0
Index: linux-2.6.13-rc6-git9/arch/ppc64/configs/pSeries_defconfig
===================================================================
@@ -593,6 +593,7 @@
 # CONFIG_DL2K is not set
 CONFIG_E1000=y
 # CONFIG_E1000_NAPI is not set
+CONFIG_E1000_EEH_RECOVERY=y
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
drivers/net/Kconfig +8 -0
Index: linux-2.6.13-rc6-git9/drivers/net/Kconfig
===================================================================
@@ -1847,6 +1847,14 @@
 
 	  If in doubt, say N.
 
+config E1000_EEH_RECOVERY
+	bool "Enable PCI bus error recovery"
+	depends on E1000 && PPC_PSERIES
+   help
+      If you say Y here, the driver will be able to recover from
+      PCI bus errors on many PowerPC platforms. IBM pSeries users
+      should answer Y.
+
 config MYRI_SBUS
 	tristate "MyriCOM Gigabit Ethernet support"
 	depends on SBUS
drivers/net/e1000/e1000_main.c +102 -1

120 lines not on this page · raw message

--

A message that is not in the archive (sent off-list or not yet received): 20050823232142.651390000@bilge

#13 lore raw

PATCH 7/8 PCI Error Recovery: ixgb network device driver

Various PCI bus errors can be signaled by newer PCI controllers. This patch adds the PCI error recovery callbacks to the intel ten-gigabit ethernet ixgb device driver. The patch has been tested, and appears to work well.

--

 arch/ppc64/configs/pSeries_defconfig |    1 
 drivers/net/Kconfig                  |    8 +++
 drivers/net/ixgb/ixgb_main.c         |   78 +++++++++++++++++++++++++++++++++++
 3 files changed, 87 insertions(+)
arch/ppc64/configs/pSeries_defconfig +1 -0
Index: linux-2.6.13-rc6-git9/arch/ppc64/configs/pSeries_defconfig
===================================================================
@@ -610,6 +610,7 @@
 #
 CONFIG_IXGB=m
 # CONFIG_IXGB_NAPI is not set
+CONFIG_IXGB_EEH_RECOVERY=y
 CONFIG_S2IO=m
 # CONFIG_S2IO_NAPI is not set
 # CONFIG_2BUFF_MODE is not set
drivers/net/Kconfig +8 -0
Index: linux-2.6.13-rc6-git9/drivers/net/Kconfig
===================================================================
@@ -2146,6 +2146,14 @@
 
 	  If in doubt, say N.
 
+config IXGB_EEH_RECOVERY
+	bool "Enable PCI bus error recovery"
+	depends on IXGB && PPC_PSERIES
+   help
+      If you say Y here, the driver will be able to recover from
+      PCI bus errors on many PowerPC platforms. IBM pSeries users
+      should answer Y.
+
 config S2IO
 	tristate "S2IO 10Gbe XFrame NIC"
 	depends on PCI
drivers/net/ixgb/ixgb_main.c +78 -0

94 lines not on this page · raw message

--

A message that is not in the archive (sent off-list or not yet received): 20050823232143.003048000@bilge

#15 lore raw

PATCH 8/8 PCI Error Recovery: PPC64 core recovery routines

Various PCI bus errors can be signaled by newer PCI controllers. The core error recovery routines are architecture dependent. This patch adds a recovery infrastructure for the PPC64 pSeries systems.

--

 arch/ppc64/kernel/Makefile     |    2 
 arch/ppc64/kernel/eeh.c        |  543 +++++++++++++++++++++++++++++------------
 arch/ppc64/kernel/eeh_driver.c |  361 +++++++++++++++++++++++++++
 arch/ppc64/kernel/eeh_event.c  |  116 ++++++++
 arch/ppc64/kernel/eeh_event.h  |   52 +++
 arch/ppc64/kernel/rtas_pci.c   |    5 
 include/asm-ppc64/eeh.h        |  105 +++++--
 include/asm-ppc64/prom.h       |   10 
 include/asm-ppc64/rtas.h       |    2 
 9 files changed, 1001 insertions(+), 195 deletions(-)
arch/ppc64/kernel/eeh.c +385 -158
Index: linux-2.6.13-rc6-git9/arch/ppc64/kernel/eeh.c
===================================================================
@@ -1,32 +1,33 @@
 /*
+ *
  * eeh.c
  * Copyright (C) 2001 Dave Engebretsen & Todd Inglett IBM Corporation
- * 
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- * 
+ *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <linux/bootmem.h>
+#include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/irq.h>
 #include <linux/list.h>
-#include <linux/mm.h>
-#include <linux/notifier.h>
 #include <linux/pci.h>
 #include <linux/proc_fs.h>
 #include <linux/rbtree.h>
 #include <linux/seq_file.h>
 #include <linux/spinlock.h>
+#include <asm/atomic.h>
 #include <asm/eeh.h>
 #include <asm/io.h>
 #include <asm/machdep.h>
@@ -34,6 +35,7 @@
 #include <asm/atomic.h>
 #include <asm/systemcfg.h>
 #include "pci.h"
+#include "eeh_event.h"
 
 #undef DEBUG
 
@@ -49,8 +51,8 @@
  *  were "empty": all reads return 0xff's and all writes are silently
  *  ignored.  EEH slot isolation events can be triggered by parity
  *  errors on the address or data busses (e.g. during posted writes),
- *  which in turn might be caused by dust, vibration, humidity,
- *  radioactivity or plain-old failed hardware.
+ *  which in turn might be caused by low voltage on the bus, dust,
+ *  vibration, humidity, radioactivity or plain-old failed hardware.
  *
  *  Note, however, that one of the leading causes of EEH slot
  *  freeze events are buggy device drivers, buggy device microcode,
@@ -75,22 +77,13 @@
 #define BUID_HI(buid) ((buid) >> 32)
 #define BUID_LO(buid) ((buid) & 0xffffffff)
 
-/* EEH event workqueue setup. */
-static DEFINE_SPINLOCK(eeh_eventlist_lock);
-LIST_HEAD(eeh_eventlist);
-static void eeh_event_handler(void *);
-DECLARE_WORK(eeh_event_wq, eeh_event_handler, NULL);
-
-static struct notifier_block *eeh_notifier_chain;
-
 /*
  * If a device driver keeps reading an MMIO register in an interrupt
  * handler after a slot isolation event has occurred, we assume it
  * is broken and panic.  This sets the threshold for how many read
  * attempts we allow before panicking.
  */
-#define EEH_MAX_FAILS	1000
-static atomic_t eeh_fail_count;
+#define EEH_MAX_FAILS	100000
 
 /* RTAS tokens */
 static int ibm_set_eeh_option;
@@ -107,6 +100,10 @@
 static int eeh_error_buf_size;
 
 /* System monitoring statistics */
+static DEFINE_PER_CPU(unsigned long, no_device);
+static DEFINE_PER_CPU(unsigned long, no_dn);
+static DEFINE_PER_CPU(unsigned long, no_cfg_addr);
+static DEFINE_PER_CPU(unsigned long, ignored_check);
 static DEFINE_PER_CPU(unsigned long, total_mmio_ffs);
 static DEFINE_PER_CPU(unsigned long, false_positives);
 static DEFINE_PER_CPU(unsigned long, ignored_failures);
@@ -224,9 +221,9 @@
 	while (*p) {
 		parent = *p;
 		piar = rb_entry(parent, struct pci_io_addr_range, rb_node);
-		if (alo < piar->addr_lo) {
+		if (ahi < piar->addr_lo) {
 			p = &parent->rb_left;
-		} else if (ahi > piar->addr_hi) {
+		} else if (alo > piar->addr_hi) {
 			p = &parent->rb_right;
 		} else {
 			if (dev != piar->pcidev ||
@@ -245,6 +242,11 @@
 	piar->pcidev = dev;
 	piar->flags = flags;
 
+#ifdef DEBUG
+	printk (KERN_DEBUG "PIAR: insert range=[%lx:%lx] dev=%s\n",
+	               alo, ahi, pci_name (dev));
+#endif
+
 	rb_link_node(&piar->rb_node, parent, p);
 	rb_insert_color(&piar->rb_node, &pci_io_addr_cache_root.rb_root);
 
@@ -268,8 +270,8 @@
 	if (!(dn->eeh_mode & EEH_MODE_SUPPORTED) ||
 	    dn->eeh_mode & EEH_MODE_NOCHECK) {
 #ifdef DEBUG
-		printk(KERN_INFO "PCI: skip building address cache for=%s\n",
-		       pci_name(dev));
+		printk(KERN_INFO "PCI: skip building address cache for=%s %s\n",
+		       pci_name(dev), dn->type);
 #endif
 		return;
 	}
@@ -368,8 +370,12 @@
  */
 void __init pci_addr_cache_build(void)
 {
+	struct device_node *dn;
 	struct pci_dev *dev = NULL;
 
+	if (!eeh_subsystem_enabled)
+		return;
+
 	spin_lock_init(&pci_io_addr_cache_root.piar_lock);
 
 	while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
@@ -378,6 +384,17 @@
 			continue;
 		}
 		pci_addr_cache_insert_device(dev);
+
+		/* Save the BAR's; firmware doesn't restore these after EEH reset */
+		dn = pci_device_to_OF_node(dev);
+		if (dn) {
+			int i;
+			for (i = 0; i < 16; i++)
+				pci_read_config_dword(dev, i * 4, &dn->config_space[i]);
+
+			if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE)
+				dn->eeh_is_bridge = 1;
+		}
 	}
 
 #ifdef DEBUG
@@ -389,24 +406,32 @@
 /* --------------------------------------------------------------- */
 /* Above lies the PCI Address Cache. Below lies the EEH event infrastructure */
 
-/**
- * eeh_register_notifier - Register to find out about EEH events.
- * @nb: notifier block to callback on events
- */
-int eeh_register_notifier(struct notifier_block *nb)
+void eeh_slot_error_detail (struct device_node *dn, int severity)
 {
-	return notifier_chain_register(&eeh_notifier_chain, nb);
-}
+	unsigned long flags;
+	int rc;
 
-/**
- * eeh_unregister_notifier - Unregister to an EEH event notifier.
- * @nb: notifier block to callback on events
- */
-int eeh_unregister_notifier(struct notifier_block *nb)
-{
-	return notifier_chain_unregister(&eeh_notifier_chain, nb);
+	if (!dn) return;
+
+	/* Log the error with the rtas logger */
+	spin_lock_irqsave(&slot_errbuf_lock, flags);
+	memset(slot_errbuf, 0, eeh_error_buf_size);
+
+	rc = rtas_call(ibm_slot_error_detail,
+	               8, 1, NULL, dn->eeh_config_addr,
+	               BUID_HI(dn->phb->buid),
+	               BUID_LO(dn->phb->buid), NULL, 0,
+	               virt_to_phys(slot_errbuf),
+	               eeh_error_buf_size,
+	               severity);
+
+	if (rc == 0)
+		log_error(slot_errbuf, ERR_TYPE_RTAS_LOG, 0);
+	spin_unlock_irqrestore(&slot_errbuf_lock, flags);
 }
 
+EXPORT_SYMBOL(eeh_slot_error_detail);
+
 /**
  * read_slot_reset_state - Read the reset state of a device node's slot
  * @dn: device node to read
@@ -421,6 +446,7 @@
 		outputs = 4;
 	} else {
 		token = ibm_read_slot_reset_state;
+		rets[2] = 0; /* fake PE Unavailable info */
 		outputs = 3;
 	}
 
@@ -429,75 +455,8 @@
 }
 
 /**
- * eeh_panic - call panic() for an eeh event that cannot be handled.
- * The philosophy of this routine is that it is better to panic and
- * halt the OS than it is to risk possible data corruption by
- * oblivious device drivers that don't know better.
- *
- * @dev pci device that had an eeh event
- * @reset_state current reset state of the device slot
- */
-static void eeh_panic(struct pci_dev *dev, int reset_state)
-{
-	/*
-	 * XXX We should create a separate sysctl for this.
-	 *
-	 * Since the panic_on_oops sysctl is used to halt the system
-	 * in light of potential corruption, we can use it here.
-	 */
-	if (panic_on_oops)
-		panic("EEH: MMIO failure (%d) on device:%s\n", reset_state,
-		      pci_name(dev));
-	else {
-		__get_cpu_var(ignored_failures)++;
-		printk(KERN_INFO "EEH: Ignored MMIO failure (%d) on device:%s\n",
-		       reset_state, pci_name(dev));
-	}
-}
-
-/**
- * eeh_event_handler - dispatch EEH events.  The detection of a frozen
- * slot can occur inside an interrupt, where it can be hard to do
- * anything about it.  The goal of this routine is to pull these
- * detection events out of the context of the interrupt handler, and
- * re-dispatch them for processing at a later time in a normal context.
- *
- * @dummy - unused
- */
-static void eeh_event_handler(void *dummy)
-{
-	unsigned long flags;
-	struct eeh_event	*event;
-
-	while (1) {
-		spin_lock_irqsave(&eeh_eventlist_lock, flags);
-		event = NULL;
-		if (!list_empty(&eeh_eventlist)) {
-			event = list_entry(eeh_eventlist.next, struct eeh_event, list);
-			list_del(&event->list);
-		}
-		spin_unlock_irqrestore(&eeh_eventlist_lock, flags);
-		if (event == NULL)
-			break;
-
-		printk(KERN_INFO "EEH: MMIO failure (%d), notifiying device "
-		       "%s\n", event->reset_state,
-		       pci_name(event->dev));
-
-		atomic_set(&eeh_fail_count, 0);
-		notifier_call_chain (&eeh_notifier_chain,
-				     EEH_NOTIFY_FREEZE, event);
-
-		__get_cpu_var(slot_resets)++;
-
-		pci_dev_put(event->dev);
-		kfree(event);
-	}
-}
-
-/**
- * eeh_token_to_phys - convert EEH address token to phys address
- * @token i/o token, should be address in the form 0xE....
+ * eeh_token_to_phys - convert I/O address to phys address
+ * @token i/o token, should be address in the form 0xA....
  */
 static inline unsigned long eeh_token_to_phys(unsigned long token)
 {
@@ -512,6 +471,39 @@
 	return pa | (token & (PAGE_SIZE-1));
 }
 
+/** Mark all devices that are peers of this device as failed.
+ *  Mark the device driver too, so that it can see the failure
+ *  immediately; this is critical, since some drivers poll
+ *  status registers in interrupts ... If a driver is polling,
+ *  and the slot is frozen, then the driver can deadlock in
+ *  an interrupt context, which is bad.
+ */
+static inline void eeh_mark_slot (struct device_node *dn)
+{
+	while (dn) {
+		dn->eeh_mode |= EEH_MODE_ISOLATED;
+
+		/* Mark the pci device driver too */
+		struct pci_dev *dev = dn->pcidev;
+		if (dev && dev->driver) {
+			dev->error_state = pci_channel_io_frozen;
+		}
+		if (dn->child)
+			eeh_mark_slot (dn->child);
+		dn = dn->sibling;
+	}
+}
+
+static inline void eeh_clear_slot (struct device_node *dn)
+{
+	while (dn) {
+		dn->eeh_mode &= ~(EEH_MODE_RECOVERING|EEH_MODE_ISOLATED);
+		if (dn->child)
+			eeh_clear_slot (dn->child);
+		dn = dn->sibling;
+	}
+}
+
 /**
  * eeh_dn_check_failure - check if all 1's data is due to EEH slot freeze
  * @dn device node
@@ -527,29 +519,37 @@
  *
  * It is safe to call this routine in an interrupt context.
  */
+extern void disable_irq_nosync(unsigned int);
+
 int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev)
 {
 	int ret;
 	int rets[3];
-	unsigned long flags;
-	int rc, reset_state;
-	struct eeh_event  *event;
+	enum pci_channel_state state;
 
 	__get_cpu_var(total_mmio_ffs)++;
 
 	if (!eeh_subsystem_enabled)
 		return 0;
 
-	if (!dn)
+	if (!dn) {
+		__get_cpu_var(no_dn)++;
 		return 0;
+	}
 
 	/* Access to IO BARs might get this far and still not want checking. */
 	if (!(dn->eeh_mode & EEH_MODE_SUPPORTED) ||
 	    dn->eeh_mode & EEH_MODE_NOCHECK) {
+		__get_cpu_var(ignored_check)++;
+#ifdef DEBUG
+		printk ("EEH:ignored check for %s %s\n",
+		           pci_name (dev), dn->full_name);
+#endif
 		return 0;
 	}
 
 	if (!dn->eeh_config_addr) {
+		__get_cpu_var(no_cfg_addr)++;
 		return 0;
 	}
 
@@ -558,12 +558,18 @@
 	 * slot, we know it's bad already, we don't need to check...
 	 */
 	if (dn->eeh_mode & EEH_MODE_ISOLATED) {
-		atomic_inc(&eeh_fail_count);
-		if (atomic_read(&eeh_fail_count) >= EEH_MAX_FAILS) {
+		dn->eeh_check_count ++;
+		if (dn->eeh_check_count >= EEH_MAX_FAILS) {
+			printk (KERN_ERR "EEH: Device driver ignored %d bad reads, panicing\n",
+			        dn->eeh_check_count);
+			dump_stack();
 			/* re-read the slot reset state */
 			if (read_slot_reset_state(dn, rets) != 0)
 				rets[0] = -1;	/* reset state unknown */
-			eeh_panic(dev, rets[0]);
+
+			/* If we are here, then we hit an infinite loop. Stop. */
+			panic("EEH: MMIO halt (%d) on device:%s\n", rets[0],
+		      pci_name(dev));
 		}
 		return 0;
 	}
@@ -576,53 +582,36 @@
 	 * In any case they must share a common PHB.
 	 */
 	ret = read_slot_reset_state(dn, rets);
-	if (!(ret == 0 && rets[1] == 1 && (rets[0] == 2 || rets[0] == 4))) {
+	if (!(ret == 0 && ((rets[1] == 1 && (rets[0] == 2 || rets[0] >= 4))
+	                   || (rets[0] == 5)))) {
 		__get_cpu_var(false_positives)++;
 		return 0;
 	}
 
-	/* prevent repeated reports of this failure */
-	dn->eeh_mode |= EEH_MODE_ISOLATED;
-
-	reset_state = rets[0];
-
-	spin_lock_irqsave(&slot_errbuf_lock, flags);
-	memset(slot_errbuf, 0, eeh_error_buf_size);
-
-	rc = rtas_call(ibm_slot_error_detail,
-	               8, 1, NULL, dn->eeh_config_addr,
-	               BUID_HI(dn->phb->buid),
-	               BUID_LO(dn->phb->buid), NULL, 0,
-	               virt_to_phys(slot_errbuf),
-	               eeh_error_buf_size,
-	               1 /* Temporary Error */);
+	/* Note that empty slots will fail; empty slots don't have children... */
+	if ((rets[0] == 5) && (dn->child == NULL)) {
+		__get_cpu_var(false_positives)++;
+		return 0;
+	}
 
-	if (rc == 0)
-		log_error(slot_errbuf, ERR_TYPE_RTAS_LOG, 0);
-	spin_unlock_irqrestore(&slot_errbuf_lock, flags);
+	/* Avoid repeated reports of this failure, including problems
+	 * with other functions on this device, and functions under
+	 * bridges. */
+	eeh_mark_slot (dn->parent->child);
+	__get_cpu_var(slot_resets)++;
+
+	state = pci_channel_io_normal;
+	if ((rets[0] == 2) || (rets[0] == 4))
+		state = pci_channel_io_frozen;
+	if (rets[0] == 5)
+		state = pci_channel_io_perm_failure;
 
-	printk(KERN_INFO "EEH: MMIO failure (%d) on device: %s %s\n",
-	       rets[0], dn->name, dn->full_name);
-	event = kmalloc(sizeof(*event), GFP_ATOMIC);
-	if (event == NULL) {
-		eeh_panic(dev, reset_state);
-		return 1;
- 	}
-
-	event->dev = dev;
-	event->dn = dn;
-	event->reset_state = reset_state;
-
-	/* We may or may not be called in an interrupt context */
-	spin_lock_irqsave(&eeh_eventlist_lock, flags);
-	list_add(&event->list, &eeh_eventlist);
-	spin_unlock_irqrestore(&eeh_eventlist_lock, flags);
+	eeh_send_failure_event (dn, dev, state, rets[2]);
 
 	/* Most EEH events are due to device driver bugs.  Having
 	 * a stack trace will help the device-driver authors figure
 	 * out what happened.  So print that out. */
-	dump_stack();
-	schedule_work(&eeh_event_wq);
+	if (rets[0] != 5) dump_stack();
 
 	return 0;
 }
@@ -634,7 +623,6 @@
  * @token i/o token, should be address in the form 0xA....
  * @val value, should be all 1's (XXX why do we need this arg??)
  *
- * Check for an eeh failure at the given token address.
  * Check for an EEH failure at the given token address.  Call this
  * routine if the result of a read was all 0xff's and you want to
  * find out if this is due to an EEH slot freeze event.  This routine
@@ -651,8 +639,10 @@
 	/* Finding the phys addr + pci device; this is pretty quick. */
 	addr = eeh_token_to_phys((unsigned long __force) token);
 	dev = pci_get_device_by_addr(addr);
-	if (!dev)
+	if (!dev) {
+		__get_cpu_var(no_device)++;
 		return val;
+	}
 
 	dn = pci_device_to_OF_node(dev);
 	eeh_dn_check_failure (dn, dev);
@@ -663,6 +653,209 @@
 
 EXPORT_SYMBOL(eeh_check_failure);
 
+/* ------------------------------------------------------------- */
+/* The code below deals with error recovery */
+
+/** eeh_pci_slot_reset -- raises/lowers the pci #RST line
+ *  state: 1/0 to raise/lower the #RST
+ */
+void
+eeh_pci_slot_reset(struct pci_dev *dev, int state)
+{
+	struct device_node *dn = pci_device_to_OF_node(dev);
+	rtas_pci_slot_reset (dn, state);
+}
+
+/** Return negative value if a permanent error, else return
+ * a number of milliseconds to wait until the PCI slot is
+ * ready to be used.
+ */
+static int
+eeh_slot_availability(struct device_node *dn)
+{
+	int rc;
+	int rets[3];
+
+	rc = read_slot_reset_state(dn, rets);
+
+	if (rc) return rc;
+
+	if (rets[1] == 0) return -1;  /* EEH is not supported */
+	if (rets[0] == 0)  return 0;  /* Oll Korrect */
+	if (rets[0] == 5) {
+		if (rets[2] == 0) return -1; /* permanently unavailable */
+		return rets[2]; /* number of millisecs to wait */
+	}
+	return -1;
+}
+
+int
+eeh_pci_slot_availability(struct pci_dev *dev)
+{
+	struct device_node *dn = pci_device_to_OF_node(dev);
+	if (!dn) return -1;
+
+	BUG_ON (dn->phb==NULL);
+	if (dn->phb==NULL) {
+		printk (KERN_ERR "EEH, checking on slot with no phb dn=%s dev=%s\n",
+		       dn->full_name, pci_name(dev));
+		return -1;
+	}
+	return eeh_slot_availability (dn);
+}
+
+void
+rtas_pci_slot_reset(struct device_node *dn, int state)
+{
+	int rc;
+
+	if (!dn)
+		return;
+	if (!dn->phb) {
+		printk (KERN_WARNING "EEH: in slot reset, device node %s has no phb\n",                    dn->full_name);
+		return;
+	}
+
+	dn->eeh_mode |= EEH_MODE_RECOVERING;
+	rc = rtas_call(ibm_set_slot_reset,4,1, NULL,
+	               dn->eeh_config_addr,
+	               BUID_HI(dn->phb->buid),
+	               BUID_LO(dn->phb->buid),
+	               state);
+	if (rc) {
+		printk (KERN_WARNING "EEH: Unable to reset the failed slot, (%d) #RST=%d\n", rc, state);
+		return;
+	}
+
+	if (state == 0)
+		eeh_clear_slot (dn->parent->child);
+}
+
+/** rtas_set_slot_reset -- assert the pci #RST line for 1/4 second
+ *  dn -- device node to be reset.
+ */
+
+void
+rtas_set_slot_reset(struct device_node *dn)
+{
+	int i, rc;
+
+	rtas_pci_slot_reset (dn, 1);
+
+	/* The PCI bus requires that the reset be held high for at least
+	 * a 100 milliseconds. We wait a bit longer 'just in case'.  */
+
+#define PCI_BUS_RST_HOLD_TIME_MSEC 250
+	msleep (PCI_BUS_RST_HOLD_TIME_MSEC);
+	rtas_pci_slot_reset (dn, 0);
+
+	/* After a PCI slot has been reset, the PCI Express spec requires
+	 * a 1.5 second idle time for the bus to stabilize, before starting
+	 * up traffic. */
+#define PCI_BUS_SETTLE_TIME_MSEC 1800
+	msleep (PCI_BUS_SETTLE_TIME_MSEC);
+
+	/* Now double check with the firmware to make sure the device is
+	 * ready to be used; if not, wait for recovery. */
+	for (i=0; i<10; i++) {
+		rc = eeh_slot_availability (dn);
+		if (rc <= 0) break;
+
+		msleep (rc+100);
+	}
+}
+
+EXPORT_SYMBOL(rtas_set_slot_reset);
+
+void
+rtas_configure_bridge(struct device_node *dn)
+{
+	int token = rtas_token ("ibm,configure-bridge");
+	int rc;
+
+	if (token == RTAS_UNKNOWN_SERVICE)
+		return;
+	rc = rtas_call(token,3,1, NULL,
+	               dn->eeh_config_addr,
+	               BUID_HI(dn->phb->buid),
+	               BUID_LO(dn->phb->buid));
+	if (rc) {
+		printk (KERN_WARNING "EEH: Unable to configure device bridge (%d) for %s\n",
+		        rc, dn->full_name);
+	}
+}
+
+EXPORT_SYMBOL(rtas_configure_bridge);
+
+/* ------------------------------------------------------- */
+/** Save and restore of PCI BARs
+ *
+ * Although firmware will set up BARs during boot, it doesn't
+ * set up device BAR's after a device reset, although it will,
+ * if requested, set up bridge configuration. Thus, we need to
+ * configure the PCI devices ourselves.  Config-space setup is
+ * stored in the PCI structures which are normally deleted during
+ * device removal.  Thus, the "save" routine references the
+ * structures so that they aren't deleted.
+ */
+
+/**
+ * __restore_bars - Restore the Base Address Registers
+ * Loads the PCI configuration space base address registers,
+ * the expansion ROM base address, the latency timer, and etc.
+ * from the saved values in the device node.
+ */
+static inline void __restore_bars (struct device_node *dn)
+{
+	int i;
+
+	if (NULL==dn->phb) return;
+	for (i=4; i<10; i++) {
+		rtas_write_config(dn, i*4, 4, dn->config_space[i]);
+	}
+
+	/* 12 == Expansion ROM Address */
+	rtas_write_config(dn, 12*4, 4, dn->config_space[12]);
+
+#define BYTE_SWAP(OFF) (8*((OFF)/4)+3-(OFF))
+#define SAVED_BYTE(OFF) (((u8 *)(dn->config_space))[BYTE_SWAP(OFF)])
+
+	rtas_write_config (dn, PCI_CACHE_LINE_SIZE, 1,
+	            SAVED_BYTE(PCI_CACHE_LINE_SIZE));
+
+	rtas_write_config (dn, PCI_LATENCY_TIMER, 1,
+	            SAVED_BYTE(PCI_LATENCY_TIMER));
+
+	/* max latency, min grant, interrupt pin and line */
+	rtas_write_config(dn, 15*4, 4, dn->config_space[15]);
+}
+
+/**
+ * eeh_restore_bars - restore the PCI config space info
+ */
+void eeh_restore_bars(struct device_node *dn)
+{
+	if (! dn->eeh_is_bridge)
+		__restore_bars (dn);
+
+	if (dn->child)
+		eeh_restore_bars (dn->child);
+}
+
+void eeh_pci_restore_bars(struct pci_dev *dev)
+{
+	struct device_node *dn = pci_device_to_OF_node(dev);
+	eeh_restore_bars (dn);
+}
+
+/* ------------------------------------------------------------- */
+/* The code below deals with enabling EEH for devices during  the
+ * early boot sequence.  EEH must be enabled before any PCI probing
+ * can be done.
+ */
+
+#define EEH_ENABLE 1
+
 struct eeh_early_enable_info {
 	unsigned int buid_hi;
 	unsigned int buid_lo;
@@ -681,6 +874,8 @@
 	int enable;
 
 	dn->eeh_mode = 0;
+	dn->eeh_check_count = 0;
+	dn->eeh_freeze_count = 0;
 
 	if (status && strcmp(status, "ok") != 0)
 		return NULL;	/* ignore devices with bad status */
@@ -704,8 +899,10 @@
 	 * But there are a few cases like display devices that make sense.
 	 */
 	enable = 1;	/* i.e. we will do checking */
+#if 0
 	if ((*class_code >> 16) == PCI_BASE_CLASS_DISPLAY)
 		enable = 0;
+#endif
 
 	if (!enable)
 		dn->eeh_mode |= EEH_MODE_NOCHECK;
@@ -742,7 +939,7 @@
 		       dn->full_name);
 	}
 
-	return NULL; 
+	return NULL;
 }
 
 /*
@@ -827,7 +1024,9 @@
 		return;
 	phb = dn->phb;
 	if (NULL == phb || 0 == phb->buid) {
-		printk(KERN_WARNING "EEH: Expected buid but found none\n");
+		printk(KERN_WARNING "EEH: Expected buid but found none for %s\n",
+		        dn->full_name);
+		dump_stack();
 		return;
 	}
 
@@ -846,6 +1045,9 @@
  */
 void eeh_add_device_late(struct pci_dev *dev)
 {
+	int i;
+	struct device_node *dn;
+
 	if (!dev || !eeh_subsystem_enabled)
 		return;
 
@@ -854,6 +1056,17 @@
 #endif
 
 	pci_addr_cache_insert_device (dev);
+
+	/* Save the BAR's; firmware doesn't restore these after EEH reset */
+	dn = pci_device_to_OF_node(dev);
+	for (i = 0; i < 16; i++)
+		pci_read_config_dword(dev, i * 4, &dn->config_space[i]);
+
+	if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE)
+		dn->eeh_is_bridge = 1;
+
+	pci_dev_get (dev);
+	dn->pcidev = dev;
 }
 EXPORT_SYMBOL(eeh_add_device_late);
 
@@ -866,6 +1079,7 @@
  */
 void eeh_remove_device(struct pci_dev *dev)
 {
+	struct device_node *dn;
 	if (!dev || !eeh_subsystem_enabled)
 		return;
 
@@ -874,6 +1088,10 @@
 	printk(KERN_DEBUG "EEH: remove device %s\n", pci_name(dev));
 #endif
 	pci_addr_cache_remove_device(dev);
+
+	dn = pci_device_to_OF_node(dev);
+	dn->pcidev = NULL;
+	pci_dev_put (dev);
 }
 EXPORT_SYMBOL(eeh_remove_device);
 
@@ -882,12 +1100,17 @@
 	unsigned int cpu;
 	unsigned long ffs = 0, positives = 0, failures = 0;
 	unsigned long resets = 0;
+	unsigned long no_dev = 0, no_dn = 0, no_cfg = 0, no_check = 0;
 
 	for_each_cpu(cpu) {
 		ffs += per_cpu(total_mmio_ffs, cpu);
 		positives += per_cpu(false_positives, cpu);
 		failures += per_cpu(ignored_failures, cpu);
 		resets += per_cpu(slot_resets, cpu);
+		no_dev += per_cpu(no_device, cpu);
+		no_dn += per_cpu(no_dn, cpu);
+		no_cfg += per_cpu(no_cfg_addr, cpu);
+		no_check += per_cpu(ignored_check, cpu);
 	}
 
 	if (0 == eeh_subsystem_enabled) {
@@ -895,13 +1118,17 @@
 		seq_printf(m, "eeh_total_mmio_ffs=%ld\n", ffs);
 	} else {
 		seq_printf(m, "EEH Subsystem is enabled\n");
-		seq_printf(m, "eeh_total_mmio_ffs=%ld\n"
+		seq_printf(m,
+				"no device=%ld\n"
+				"no device node=%ld\n"
+				"no config address=%ld\n"
+				"check not wanted=%ld\n"
+				"eeh_total_mmio_ffs=%ld\n"
 			   "eeh_false_positives=%ld\n"
 			   "eeh_ignored_failures=%ld\n"
-			   "eeh_slot_resets=%ld\n"
-				"eeh_fail_count=%d\n",
-			   ffs, positives, failures, resets,
-				eeh_fail_count.counter);
+			   "eeh_slot_resets=%ld\n",
+				no_dev, no_dn, no_cfg, no_check,
+			   ffs, positives, failures, resets);
 	}
 
 	return 0;
arch/ppc64/kernel/eeh_driver.c new file +361 -0

361 lines not on this page · raw message

arch/ppc64/kernel/eeh_event.c new file +116 -0

116 lines not on this page · raw message

arch/ppc64/kernel/eeh_event.h new file +52 -0

52 lines not on this page · raw message

arch/ppc64/kernel/rtas_pci.c +3 -2
Index: linux-2.6.13-rc6-git9/arch/ppc64/kernel/rtas_pci.c
===================================================================
@@ -58,7 +58,7 @@
 	return 0;
 }
 
-static int rtas_read_config(struct device_node *dn, int where, int size, u32 *val)
+int rtas_read_config(struct device_node *dn, int where, int size, u32 *val)
 {
 	int returnval = -1;
 	unsigned long buid, addr;
@@ -105,10 +105,11 @@
 	for (dn = busdn->child; dn; dn = dn->sibling)
 		if (dn->devfn == devfn)
 			return rtas_read_config(dn, where, size, val);
+
 	return PCIBIOS_DEVICE_NOT_FOUND;
 }
 
-static int rtas_write_config(struct device_node *dn, int where, int size, u32 val)
+int rtas_write_config(struct device_node *dn, int where, int size, u32 val)
 {
 	unsigned long buid, addr;
 	int ret;
include/asm-ppc64/eeh.h +73 -32

177 lines not on this page · raw message

include/asm-ppc64/rtas.h +2 -0
Index: linux-2.6.13-rc6-git9/include/asm-ppc64/rtas.h
===================================================================
@@ -246,4 +246,6 @@
 
 #define GLOBAL_INTERRUPT_QUEUE 9005
 
+extern int rtas_write_config(struct device_node *dn, int where, int size, u32 val);
+
 #endif /* _PPC64_RTAS_H */
include/asm-ppc64/prom.h +8 -2
Index: linux-2.6.13-rc6-git9/include/asm-ppc64/prom.h
===================================================================
@@ -135,11 +135,17 @@
 	int	busno;			/* for pci devices */
 	int	bussubno;		/* for pci devices */
 	int	devfn;			/* for pci devices */
-	int	eeh_mode;		/* See eeh.h for possible EEH_MODEs */
-	int	eeh_config_addr;
+	int   eeh_mode;      /* See eeh.h for possible EEH_MODEs */
+	int   eeh_config_addr;
+	int   eeh_check_count;    /* number of times device driver ignored error */
+	int   eeh_freeze_count;   /* number of times this device froze up. */
+	int   eeh_is_bridge;      /* device is pci-to-pci bridge */
+
 	int	pci_ext_config_space;	/* for pci devices */
 	struct  pci_controller *phb;	/* for pci devices */
 	struct	iommu_table *iommu_table;	/* for phb's or bridges */
+	struct   pci_dev *pcidev;    /* back-pointer to the pci device */
+	u32      config_space[16]; /* saved PCI config space */
 
 	struct	property *properties;
 	struct	device_node *parent;
arch/ppc64/kernel/Makefile +1 -1
Index: linux-2.6.13-rc6-git9/arch/ppc64/kernel/Makefile
===================================================================
@@ -37,7 +37,7 @@
 			 bpa_iic.o spider-pic.o
 
 obj-$(CONFIG_KEXEC)		+= machine_kexec.o
-obj-$(CONFIG_EEH)		+= eeh.o
+obj-$(CONFIG_EEH)		+= eeh.o eeh_driver.o eeh_event.o
 obj-$(CONFIG_PROC_FS)		+= proc_ppc64.o
 obj-$(CONFIG_RTAS_FLASH)	+= rtas_flash.o
 obj-$(CONFIG_SMP)		+= smp.o

--

#16 lore raw

Re: [patch 8/8] PCI Error Recovery: PPC64 core recovery routines

Linas Vepstas writes:

In this patch at least, your mailer seems to have blanked out lines that match ^[-+]$. Could you send them to me again with a different mailer or put them on a web or ftp site somewhere?

Thanks,
Paul.

#17 lore raw

Re: [patch 8/8] PCI Error Recovery: PPC64 core recovery routines

Quoted 5 lines · I wrote:

Linas Vepstas writes:

In this patch at least, your mailer seems to have blanked out lines that match ^[-+]$. Could you send them to me again with a different mailer or put them on a web or ftp site somewhere?

I got 3 copies of each of these mails, one directly, one through linuxppc64-dev and one through linux-kernel. It looks like the copies that came through the mailing lists are OK but the copy that came directly to me is corrupted. Weird.

Regards,
Paul.

#18 lore raw

Re: [patch 8/8] PCI Error Recovery: PPC64 core recovery routines

In reply to Linas Vepstas

Hi Linas-

I like the idea of splitting the recovery stuff into its own driver. A few comments on the last reorg patch:

Quoted 1 line

Index: linux-2.6.13-rc6-git9/arch/ppc64/kernel/eeh.c

...

Quoted 2 lines
arch/ppc64/kernel/eeh.c +2 -0
+static int
+eeh_slot_availability(struct device_node *dn)

...

Quoted 1 line

+void eeh_restore_bars(struct device_node *dn)

Inconsistent spacing in new code... </nit>

arch/ppc64/kernel/eeh_driver.c line 2

Quoted 5 lines
arch/ppc64/kernel/eeh_driver.c new file +2 -0
@@ -0,0 +1,361 @@
+/*
+ * PCI Hot Plug Controller Driver for RPA-compliant PPC64 platform.

This probably isn't the right header description for this file :)

Quoted 19 lines
arch/ppc64/kernel/eeh_driver.c new file +19 -0
+
+/**
+ * rpaphp_find_slot - find and return the slot holding the device
+ * @dev: pci device for which we want the slot structure.
+ */
+static struct slot *rpaphp_find_slot(struct pci_dev *dev)
+{
+	struct list_head *tmp, *n;
+	struct slot	*slot;
+
+	list_for_each_safe(tmp, n, &rpaphp_slot_head) {
+		struct pci_bus *bus;
+
+		slot = list_entry(tmp, struct slot, rpaphp_slot_list);
+
+		/* PHB's don't have bridges. */
+		bus = slot->bus;
+		if (bus == NULL)
+			continue;

arch/ppc64/kernel/eeh_driver.c line 92

Quoted 10 lines
arch/ppc64/kernel/eeh_driver.c new file +10 -0
+
+		/* The PCI device could be the slot itself. */
+		if (bus->self == dev)
+			return slot;
+
+		if (pci_search_bus_for_dev (bus, dev))
+			return slot;
+	}
+	return NULL;
+}

This function breaks if rpaphp is compiled as a module. It's probably bad for kernel code to depend on symbols exported from modules. This raises two larger questions: Where should this new driver sit, and should it be possible to compile it as a module as well?

Quoted 4 lines
arch/ppc64/kernel/eeh_driver.c new file +4 -0
+/* ------------------------------------------------------- */
+/**
+ * handle_eeh_events -- reset a PCI device after hard lockup.
+ *

...

Quoted 1 line

+int eeh_reset_device (struct pci_dev *dev, struct device_node *dn, int reconfig)

Header doesn't match the function :)

Quoted 27 lines
arch/ppc64/kernel/eeh_driver.c new file +27 -0
+{
+	struct hotplug_slot *frozen_slot= NULL;
+	struct hotplug_slot_ops *frozen_ops= NULL;
+
+	if (!dev)
+		return 1;
+
+	if (reconfig) {
+		frozen_slot = pci_hp_find_slot(dev);
+		if (frozen_slot)
+			frozen_ops = frozen_slot->ops;
+	}
+
+	if (frozen_ops) frozen_ops->disable_slot (frozen_slot);
+
+	/* Reset the pci controller. (Asserts RST#; resets config space).
+	 * Reconfigure bridges and devices */
+	rtas_set_slot_reset (dn->child);
+
+	/* Walk over all functions on this device */
+	struct device_node *peer = dn->child;
+	while (peer) {
+		rtas_configure_bridge(peer);
+		eeh_restore_bars(peer);
+		peer = peer->sibling;
+	}
+

arch/ppc64/kernel/eeh_driver.c line 233

Quoted 10 lines
arch/ppc64/kernel/eeh_driver.c new file +10 -0
+	/* Give the system 5 seconds to finish running the user-space
+	 * hotplug scripts, e.g. ifdown for ethernet.  Yes, this is a hack,
+	 * but if we don't do this, weird things happen.
+	 */
+	if (frozen_ops) {
+		ssleep (5);
+		frozen_ops->enable_slot (frozen_slot);
+	}
+	return 0;
+}

This dependence on struct hotplug_slot might be problematic as we restrict the registration of "PCI hotplug" slots to exclude PHBs, VIO, and embedded slots. Noticed your comment to this effect. I can work with you offline on this.

Quoted 9 lines
arch/ppc64/kernel/eeh_driver.c new file +9 -0
+
+/* The longest amount of time to wait for a pci device
+ * to come back on line, in seconds.
+ */
+#define MAX_WAIT_FOR_RECOVERY 15
+
+int handle_eeh_events (struct eeh_event *event)
+{
+	

...

arch/ppc64/kernel/eeh_driver.c line 272

Quoted 13 lines
arch/ppc64/kernel/eeh_driver.c new file +13 -0
+	frozen_device = pci_bus_to_OF_node(dev->bus);
+	if (!frozen_device)
+	{
+		printk (KERN_ERR "EEH: Cannot find PCI controller for %s\n",
+				pci_name(dev));
+
+		return 1;
+	}
+	BUG_ON (frozen_device->phb==NULL);
+
+	/* We get "permanent failure" messages on empty slots.
+	 * These are false alarms. Empty slots have no child dn. */
+	if ((event->state == pci_channel_io_perm_failure) && (frozen_device == NULL))

The second part of this conditional will never be true, as this has just been checked above.

arch/ppc64/kernel/eeh_driver.c line 276

Quoted 2 lines
arch/ppc64/kernel/eeh_driver.c new file +2 -0
+       if (frozen_device)
+               freeze_count = frozen_device->eeh_freeze_count;

This conditional will always be true, as this has also ben checked above.

Quoted 14 lines

Index: linux-2.6.13-rc6-git9/include/asm-ppc64/prom.h
===================================================================

include/asm-ppc64/prom.h +4 -2
@@ -135,11 +135,17 @@
 	int	busno;			/* for pci devices */
 	int	bussubno;		/* for pci devices */
 	int	devfn;			/* for pci devices */
-	int	eeh_mode;		/* See eeh.h for possible EEH_MODEs */
-	int	eeh_config_addr;
+	int   eeh_mode;      /* See eeh.h for possible EEH_MODEs */
+	int   eeh_config_addr;
+	int   eeh_check_count;    /* number of times device driver ignored error */
+	int   eeh_freeze_count;   /* number of times this device froze up. */

include/asm-ppc64/prom.h line 151

Quoted 10 lines
include/asm-ppc64/prom.h +4 -0
+	int   eeh_is_bridge;      /* device is pci-to-pci bridge */
+
 	int	pci_ext_config_space;	/* for pci devices */
 	struct  pci_controller *phb;	/* for pci devices */
 	struct	iommu_table *iommu_table;	/* for phb's or bridges */
+	struct   pci_dev *pcidev;    /* back-pointer to the pci device */
+	u32      config_space[16]; /* saved PCI config space */
 
 	struct	property *properties;
 	struct	device_node *parent;

How about a pointer to a struct of EEH fields? Folks are touchy about adding anything PCI-specific to device nodes, especially since most DNs aren't PCI at all.

Thanks-
John

#19 lore raw

Re: [patch 8/8] PCI Error Recovery: PPC64 core recovery routines

On Wed, Aug 24, 2005 at 10:45:31AM -0500, John Rose was heard to remark:

Quoted 5 lines
Quoted 3 lines

+++ linux-2.6.13-rc6-git9/arch/ppc64/kernel/eeh_driver.c 2005-08-23 14:34:44.000000000 -0500
+/*
+ * PCI Hot Plug Controller Driver for RPA-compliant PPC64 platform.

This probably isn't the right header description for this file :)

Yes, this file is a little ball of ugliness that resulted from moving things out of the rpaphp directory; and, yes, it's rather un-reconstructed. I released it under the "release early" program.

The meta-issue that I'd like to reach consensus on first is whether there should be any hot-plug recovery attempted at all. Removing hot-plug-recovery support will make many of the issues you raise to be moot.

Quoted 8 lines

include/asm-ppc64/prom.h line 137

Quoted 4 lines

+++ linux-2.6.13-rc6-git9/include/asm-ppc64/prom.h 2005-08-23 13:31:52.000000000 -0500

include/asm-ppc64/prom.h +0 -0
 	int	busno;			/* for pci devices */
 	int	bussubno;		/* for pci devices */
 	int	devfn;			/* for pci devices */

How about a pointer to a struct of EEH fields? Folks are touchy about adding anything PCI-specific to device nodes, especially since most DNs aren't PCI at all.

I attempted to remove all of the pci-related stuff from this struct, and got a crash in very very early boot (before the transition from real to virtual addressing). Not sure why, I was surprised. It seems related to the flattening of the device ndode tree. I'll try again soon.

--linas

#20 lore raw

Re: [patch 8/8] PCI Error Recovery: PPC64 core recovery routines

Quoted 4 lines · Linas Vepstas

The meta-issue that I'd like to reach consensus on first is whether there should be any hot-plug recovery attempted at all. Removing hot-plug-recovery support will make many of the issues you raise to be moot.

Yes, this probably the thorniest issue we have.

My feeling is that the unplug half of it is probably fairly uncontroversial, but the replug half is a can of worms. Would you agree with that?

Is it udev that handles the hotplug notifications on the userspace side in all cases (do both RHEL and SLES use udev, for instance)? How hard is it to add a new sort of notification, on the kernel side and in udev?

I think what I'd like to see is that when a slot gets isolated and the driver doesn't have recovery code, the kernel calls the driver's unplug function and generates a hotplug event to udev. Ideally this would be a variant of the remove event which would say "and by the way, please try replugging this slot when you've finished handling the remove event" or something along those lines.

Thoughts?

Paul.

#21 lore raw

Re: [patch 8/8] PCI Error Recovery: PPC64 core recovery routines

Quoted 7 lines

I think what I'd like to see is that when a slot gets isolated and the driver doesn't have recovery code, the kernel calls the driver's unplug function and generates a hotplug event to udev. Ideally this would be a variant of the remove event which would say "and by the way, please try replugging this slot when you've finished handling the remove event" or something along those lines.

I'm still trying to understand why we care. What prevents us from just uplugging the previous device and re-plugging right away ? After all, the driver->remove() function is supposed to guarantee that no HW access will happen after it returns and that everything was unmapped.

Of course, we'll possibly end up with a different ethX or whatever, but I don't see the problem with that ... It's hopeless to think we might manage to keep that identical anyway, unless the driver implements proper error recovery.

Ben.

#22 lore raw

Re: [patch 8/8] PCI Error Recovery: PPC64 core recovery routines

On Thu, Aug 25, 2005 at 10:49:03AM +1000, Benjamin Herrenschmidt was heard to remark:

Quoted 2 lines

Of course, we'll possibly end up with a different ethX or whatever, but

Yep, but that's not an issue, since all the various device-naming schemes are supposed to be fixing this. Its a distinct problem; it needs to be solved even across cold-boots.

(Didn't I ever tell you about the day I added a new disk controller to my system, and /dev/hda became /dev/hde and thus /home was mounted on /usr and /var as /etc and all hell broke loose? Owww, device naming is a serious issue for home users and even more so for enterprise-class users).

--linas

#23 lore raw

Re: [patch 8/8] PCI Error Recovery: PPC64 core recovery routines

Quoted 7 lines · Linas Vepstas

On Thu, Aug 25, 2005 at 10:49:03AM +1000, Benjamin Herrenschmidt was heard to remark:

Quoted 2 lines

Of course, we'll possibly end up with a different ethX or whatever, but

Yep, but that's not an issue, since all the various device-naming schemes are supposed to be fixing this. Its a distinct problem; it needs to be solved even across cold-boots.

Ok, so what is the problem then ? Why do we have to wait at all ? Why not just unplug/replug right away ?

Quoted 8 lines

(Didn't I ever tell you about the day I added a new disk controller to my system, and /dev/hda became /dev/hde and thus /home was mounted on /usr and /var as /etc and all hell broke loose? Owww, device naming is a serious issue for home users and even more so for enterprise-class users).

--linas

#24 lore raw

Re: [patch 8/8] PCI Error Recovery: PPC64 core recovery routines

Quoted 2 lines · Benjamin Herrenschmidt

Ok, so what is the problem then ? Why do we have to wait at all ? Why not just unplug/replug right away ?

We'd have to be absolutely certain that the driver could not possibly take another interrupt or try to access the device on behalf of the old instance of the device by the time it returned from the remove function. I'm not sure I'd trust most drivers that far...

Paul.

#25 lore raw

Re: [patch 8/8] PCI Error Recovery: PPC64 core recovery routines

Quoted 9 lines · Paul Mackerras
Quoted 2 lines · Benjamin Herrenschmidt

Ok, so what is the problem then ? Why do we have to wait at all ? Why not just unplug/replug right away ?

We'd have to be absolutely certain that the driver could not possibly take another interrupt or try to access the device on behalf of the old instance of the device by the time it returned from the remove function. I'm not sure I'd trust most drivers that far...

Hrm... If a driver gets that wrong, then it will also blow up when unloaded as a module. All drivers should be fully shut down by the time they return from remove(). free_irq() is synchronous as is iounmap() and both of those are usually called as part of remove(). I wouldn't be too worried here.

Ben.

#26 lore raw

Re: [patch 8/8] PCI Error Recovery: PPC64 core recovery routines

On Fri, Aug 26, 2005 at 09:37:36AM +1000, Benjamin Herrenschmidt was heard to remark:

Quoted 6 lines · Paul Mackerras
Quoted 5 lines
Quoted 2 lines · Benjamin Herrenschmidt

Ok, so what is the problem then ? Why do we have to wait at all ? Why not just unplug/replug right away ?

Quoted 7 lines
Quoted 4 lines

We'd have to be absolutely certain that the driver could not possibly take another interrupt or try to access the device on behalf of the old instance of the device by the time it returned from the remove function. I'm not sure I'd trust most drivers that far...

Hrm... If a driver gets that wrong, then it will also blow up when unloaded as a module.

:) We've discovered two, so far, that blow up when unloaded:
lpfc and e1000. I beleive these are now fixed in mainline.

--linas

#27 lore raw

Re: [patch 8/8] PCI Error Recovery: PPC64 core recovery routines

In reply to Benjamin Herrenschmidt

On Fri, Aug 26, 2005 at 07:43:57AM +1000, Benjamin Herrenschmidt was heard to remark:

Quoted 11 lines · Linas Vepstas
Quoted 7 lines

On Thu, Aug 25, 2005 at 10:49:03AM +1000, Benjamin Herrenschmidt was heard to remark:

Quoted 2 lines

Of course, we'll possibly end up with a different ethX or whatever, but

Yep, but that's not an issue, since all the various device-naming schemes are supposed to be fixing this. Its a distinct problem; it needs to be solved even across cold-boots.

Ok, so what is the problem then ? Why do we have to wait at all ? Why not just unplug/replug right away ?

Paranoia + old versions of udev. I beleive that older versions of udev (such as the ones currently shipping with Red Hat RHEL4 and SuSE SLES9) failed to serialize events properly. I beleive that the newer versions do serialize, but have not verified/tested.

--linas

#28 lore raw

Re: [patch 8/8] PCI Error Recovery: PPC64 core recovery routines

In reply to Paul Mackerras

On Thu, Aug 25, 2005 at 10:10:45AM +1000, Paul Mackerras was heard to remark:

Quoted 7 lines
Quoted 4 lines · Linas Vepstas

The meta-issue that I'd like to reach consensus on first is whether there should be any hot-plug recovery attempted at all. Removing hot-plug-recovery support will make many of the issues you raise to be moot.

Quoted 5 lines

Yes, this probably the thorniest issue we have.

My feeling is that the unplug half of it is probably fairly uncontroversial, but the replug half is a can of worms. Would you agree with that?

Actually, no. There are three issues:
1) hotplug routines are called from within kernel. GregKH has stated on multiple occasions that doing this is wrong/bad/evil. This includes calling hot-unplug.

2) As a result, the code to call hot-unplug is a bit messy. In particular, there's a bit of hoop-jumping when hotplug is built as as a module (and said hoops were wrecked recently when I moved the code around, out of the rpaphp directory).

3) Hot-unplug causes scripts to run in user-space. There is no way to know when these scripts are done, so its not clear if we've waited long enough before calling hot-add (or if waiting is even necessary).

Quoted 2 lines

Is it udev that handles the hotplug notifications on the userspace side in all cases (do both RHEL and SLES use udev, for instance)?

Yes, and it seems to work fine despite the fact that the current sles9/rhel4 use rather oooooold versions of udev, which is criminal, according to Kay Seivers. I have not tested new versions of udev; I assume new versions will work "even better".

Quoted 2 lines

How hard is it to add a new sort of notification, on the kernel side and in udev?

Why? To acheive what goal? (Keep in mind that user-space eeh solutions seem to fail when the affected device is storage, since block devices and filesystems don't like the underlying storage to wink out.)

Quoted 6 lines

I think what I'd like to see is that when a slot gets isolated and the driver doesn't have recovery code, the kernel calls the driver's unplug function and generates a hotplug event to udev. Ideally this would be a variant of the remove event which would say "and by the way, please try replugging this slot when you've finished handling the remove event" or something along those lines.

Ahh, yes, this addresses the timing issue raised in point 3). However, I'm thinking that the timing issue is not really an issue, depending on how udev is designed. For example, consider a 100% cpu loaded, heavy i/o loaded PC, and now we rapidly unplug and replug some USB key. Presumably, udev will handle this gracefully. The kernel error recovery essentially looks the same to udev: the burp on the bus looks like a rapid-fire unplug-replug.

BTW, zSeries has similar concerns, where channels can come and go, causing thousands of unplug/replug udev events in rapid succession. (This was discussed on the udev mailing lists in the past). It might be interesting to have the zSeries folks discuss the current EEH design, as this is something they have far more experience with than any of the pc or unix crowd. I personally have not discussed with any zSeries people.

--linas

#29 lore raw

Re: [patch 8/8] PCI Error Recovery: PPC64 core recovery routines

Quoted 9 lines · Linas Vepstas

Actually, no. There are three issues:
1) hotplug routines are called from within kernel. GregKH has stated on multiple occasions that doing this is wrong/bad/evil. This includes calling hot-unplug.

2) As a result, the code to call hot-unplug is a bit messy. In particular, there's a bit of hoop-jumping when hotplug is built as as a module (and said hoops were wrecked recently when I moved the code around, out of the rpaphp directory).

One way to clean this up would be to make rpaphp the driver for the EADS bridges (from the pci code's point of view). Then it would automatically get included in the error recovery process and could do whatever it should.

Quoted 3 lines

3) Hot-unplug causes scripts to run in user-space. There is no way to know when these scripts are done, so its not clear if we've waited long enough before calling hot-add (or if waiting is even necessary).

OK, so let's just add a new hotplug event called KOBJ_ERROR or something, which tells userspace that an error has occurred which has made the device inaccessible. Greg, would that be OK?

The only trouble with that is that if we don't have a hotplug bridge driver loaded for the slot, we can't tell the driver that its device has gone away. I guess that's not a big problem in practice.

Paul.

#30 lore raw

Re: [patch 8/8] PCI Error Recovery: PPC64 core recovery routines

On Mon, Aug 29, 2005 at 04:40:20PM +1000, Paul Mackerras was heard to remark:

Quoted 7 lines
Quoted 5 lines · Linas Vepstas

Actually, no. There are three issues:
1) hotplug routines are called from within kernel. GregKH has stated on multiple occasions that doing this is wrong/bad/evil. This includes calling hot-unplug.

Quoted 7 lines
Quoted 4 lines

2) As a result, the code to call hot-unplug is a bit messy. In particular, there's a bit of hoop-jumping when hotplug is built as as a module (and said hoops were wrecked recently when I moved the code around, out of the rpaphp directory).

One way to clean this up would be to make rpaphp the driver for the EADS bridges (from the pci code's point of view).

I guess I don't understand what that means. Are you suggesting moving pSeries_pci.c into the rpaphp code directory?

Quoted 3 lines

Then it would
automatically get included in the error recovery process and could do whatever it should.

John Rose, the current maintainer of the rpaphp code, is pretty militant about removing things from, not adding things to, the rpaphp code. Which is a good idea, as chunks of that code are spaghetti, and do need simplification and cleanup.

Quoted 7 lines
Quoted 3 lines

3) Hot-unplug causes scripts to run in user-space. There is no way to know when these scripts are done, so its not clear if we've waited long enough before calling hot-add (or if waiting is even necessary).

OK, so let's just add a new hotplug event called KOBJ_ERROR or something, which tells userspace that an error has occurred which has made the device inaccessible. Greg, would that be OK?

Why do we need such an event?

I would prefer to deprecate the hot-plug based recovery scheme. This is for many reasons, including the fact that some devices that can get pci errors are soldered onto the planar, and are not hot-pluggable.

--linas

#31 lore raw

Re: [patch 8/8] PCI Error Recovery: PPC64 core recovery routines

Quoted 5 lines · Linas Vepstas
Quoted 2 lines

One way to clean this up would be to make rpaphp the driver for the EADS bridges (from the pci code's point of view).

I guess I don't understand what that means. Are you suggesting moving pSeries_pci.c into the rpaphp code directory?

No, not at all. :)

I'm suggesting that the rpaphp code has a struct pci_driver whose id_table and probe function are such that it will claim the EADS bridges. (It would probably be best to match on vendor=IBM and class=PCI-PCI bridge and let the probe function figure out which of the bridges it gets asked about are actually EADS bridges.)

Quoted 3 lines

I would prefer to deprecate the hot-plug based recovery scheme. This is for many reasons, including the fact that some devices that can get pci errors are soldered onto the planar, and are not hot-pluggable.

Those devices can still be isolated and reset, can they not? And they still have an EADS bridge above them, don't they? Are there any that can't be dynamically reassigned from one partition to another? I.e., they may not be physically hotpluggable but they are still virtually hotpluggable as far as the partition is concerned, IIUC.

Paul.

#32 lore raw

Re: [patch 8/8] PCI Error Recovery: PPC64 core recovery routines

Hi Paul-

Quoted 5 lines

I'm suggesting that the rpaphp code has a struct pci_driver whose id_table and probe function are such that it will claim the EADS bridges. (It would probably be best to match on vendor=IBM and class=PCI-PCI bridge and let the probe function figure out which of the bridges it gets asked about are actually EADS bridges.)

Wouldn't this leave out hotplug-capable adapters who have direct PHB parents, since these parent PHBs don't have pci_devs? Thoughts?

Thanks-
John

#33 lore raw

Re: [patch 8/8] PCI Error Recovery: PPC64 core recovery routines

In reply to Paul Mackerras

Hi Paul-

Quoted 9 lines
Quoted 4 lines

2) As a result, the code to call hot-unplug is a bit messy. In particular, there's a bit of hoop-jumping when hotplug is built as as a module (and said hoops were wrecked recently when I moved the code around, out of the rpaphp directory).

One way to clean this up would be to make rpaphp the driver for the EADS bridges (from the pci code's point of view). Then it would automatically get included in the error recovery process and could do whatever it should.

Not sure that I agree with this. Not all PCI hotplug slots have EADS devices as parents. This sort of topography dependency is something we're trying to break in rpaphp. Rpaphp could set this up for devices that do have EADS parents, but then we've only covered a subset of EEH-capable devices.

Anyway, isn't the OS forbidden from performing most of the expected function of such a driver for EADS devices:
Enable the device
Access device configuration space
Discover resources (addresses and IRQ numbers) provided by the device Allocate these resources
Communicate with the device
Disable the device

Thanks-
John

#34 lore raw

Re: [patch 8/8] PCI Error Recovery: PPC64 core recovery routines

Quoted 2 lines

Not sure that I agree with this. Not all PCI hotplug slots have EADS devices as parents.

Ahem, "PCI hotplug" above should read "EEH-enabled".

Sorry :)

John