Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6dee3fb9 authored by Linas Vepstas's avatar Linas Vepstas Committed by Paul Mackerras
Browse files

[PATCH] ppc64: PCI reset support routines



13-eeh-recovery-support-routines.patch

EEH Recovery support routines

This patch adds routines required to help drive the recovery of
EEH-frozen slots.  The main function is to drive the PCI #RST
signal line high for a qurter of a second, and then allow for
a second & a half of settle time.

Signed-off-by: default avatarLinas Vepstas <linas@austin.ibm.com>
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
parent 172ca926
Loading
Loading
Loading
Loading
+99 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 */

#include <linux/delay.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/pci.h>
@@ -676,6 +677,104 @@ unsigned long eeh_check_failure(const volatile void __iomem *token, unsigned lon

EXPORT_SYMBOL(eeh_check_failure);

/* ------------------------------------------------------------- */
/* The code below deals with error recovery */

/** 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 pci_dn *pdn)
{
	int rc;
	int rets[3];

	rc = read_slot_reset_state(pdn, 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;
}

/** rtas_pci_slot_reset raises/lowers the pci #RST line
 *  state: 1/0 to raise/lower the #RST
 *
 * Clear the EEH-frozen condition on a slot.  This routine
 * asserts the PCI #RST line if the 'state' argument is '1',
 * and drops the #RST line if 'state is '0'.  This routine is
 * safe to call in an interrupt context.
 *
 */

static void
rtas_pci_slot_reset(struct pci_dn *pdn, int state)
{
	int rc;

	BUG_ON (pdn==NULL); 

	if (!pdn->phb) {
		printk (KERN_WARNING "EEH: in slot reset, device node %s has no phb\n",
		        pdn->node->full_name);
		return;
	}

	rc = rtas_call(ibm_set_slot_reset,4,1, NULL,
	               pdn->eeh_config_addr,
	               BUID_HI(pdn->phb->buid),
	               BUID_LO(pdn->phb->buid),
	               state);
	if (rc) {
		printk (KERN_WARNING "EEH: Unable to reset the failed slot, (%d) #RST=%d dn=%s\n", 
		        rc, state, pdn->node->full_name);
		return;
	}

	if (state == 0)
		eeh_clear_slot (pdn->node->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 pci_dn *pdn)
{
	int i, rc;

	rtas_pci_slot_reset (pdn, 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 (pdn, 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 (pdn);
		if (rc <= 0) break;

		msleep (rc+100);
	}
}

/* ------------------------------------------------------------- */
/* The code below deals with enabling EEH for devices during  the
 * early boot sequence.  EEH must be enabled before any PCI probing
+14 −0
Original line number Diff line number Diff line
@@ -52,4 +52,18 @@ extern unsigned long pci_probe_only;
extern unsigned long pci_assign_all_buses;
extern int pci_read_irq_line(struct pci_dev *pci_dev);

/* ---- EEH internal-use-only related routines ---- */
#ifdef CONFIG_EEH
/**
 * rtas_set_slot_reset -- unfreeze a frozen slot
 *
 * Clear the EEH-frozen condition on a slot.  This routine
 * does this by asserting the PCI #RST line for 1/8th of
 * a second; this routine will sleep while the adapter is
 * being reset.
 */
void rtas_set_slot_reset (struct pci_dn *);

#endif

#endif /* _ASM_POWERPC_PPC_PCI_H */