Module Name:    src
Committed By:   hannken
Date:           Sun Feb 13 11:20:12 UTC 2011

Modified Files:
        src/sys/dev/pci: piixpm.c piixpmreg.h

Log Message:
The ServerWorks CSB5 smbus controller often times out and hangs until reboot.

Increase the delay between setting the command register and reading the
status register.  Reset the smbus controller if it has timed out.

Tested on an IBM eServer x335.


To generate a diff of this commit:
cvs rdiff -u -r1.34 -r1.35 src/sys/dev/pci/piixpm.c
cvs rdiff -u -r1.4 -r1.5 src/sys/dev/pci/piixpmreg.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/pci/piixpm.c
diff -u src/sys/dev/pci/piixpm.c:1.34 src/sys/dev/pci/piixpm.c:1.35
--- src/sys/dev/pci/piixpm.c:1.34	Thu Feb 10 13:52:36 2011
+++ src/sys/dev/pci/piixpm.c	Sun Feb 13 11:20:12 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: piixpm.c,v 1.34 2011/02/10 13:52:36 hannken Exp $ */
+/* $NetBSD: piixpm.c,v 1.35 2011/02/13 11:20:12 hannken Exp $ */
 /*	$OpenBSD: piixpm.c,v 1.20 2006/02/27 08:25:02 grange Exp $	*/
 
 /*
@@ -22,7 +22,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: piixpm.c,v 1.34 2011/02/10 13:52:36 hannken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: piixpm.c,v 1.35 2011/02/13 11:20:12 hannken Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -49,6 +49,9 @@
 #define DPRINTF(x)
 #endif
 
+#define PIIXPM_IS_CSB5(id) \
+	(PCI_VENDOR((id)) == PCI_VENDOR_SERVERWORKS && \
+	PCI_PRODUCT((id)) == PCI_PRODUCT_SERVERWORKS_CSB5)
 #define PIIXPM_DELAY	200
 #define PIIXPM_TIMEOUT	1
 
@@ -65,6 +68,7 @@
 
 	pci_chipset_tag_t	sc_pc;
 	pcitag_t		sc_pcitag;
+	pcireg_t		sc_id;
 
 	struct i2c_controller	sc_i2c_tag;
 	krwlock_t		sc_i2c_rwlock;
@@ -85,6 +89,7 @@
 static bool	piixpm_suspend(device_t, const pmf_qual_t *);
 static bool	piixpm_resume(device_t, const pmf_qual_t *);
 
+static void	piixpm_csb5_reset(void *);
 static int	piixpm_i2c_acquire_bus(void *, int);
 static void	piixpm_i2c_release_bus(void *, int);
 static int	piixpm_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *,
@@ -144,6 +149,7 @@
 	const char *intrstr = NULL;
 
 	sc->sc_dev = self;
+	sc->sc_id = pa->pa_id;
 	sc->sc_pc = pa->pa_pc;
 	sc->sc_pcitag = pa->pa_tag;
 
@@ -266,6 +272,27 @@
 	return true;
 }
 
+static void
+piixpm_csb5_reset(void *arg)
+{
+	struct piixpm_softc *sc = arg;
+	pcireg_t base, hostc, pmbase;
+
+	base = pci_conf_read(sc->sc_pc, sc->sc_pcitag, PIIX_SMB_BASE);
+	hostc = pci_conf_read(sc->sc_pc, sc->sc_pcitag, PIIX_SMB_HOSTC);
+
+	pmbase = pci_conf_read(sc->sc_pc, sc->sc_pcitag, PIIX_PM_BASE);
+	pmbase |= PIIX_PM_BASE_CSB5_RESET;
+	pci_conf_write(sc->sc_pc, sc->sc_pcitag, PIIX_PM_BASE, pmbase);
+	pmbase &= ~PIIX_PM_BASE_CSB5_RESET;
+	pci_conf_write(sc->sc_pc, sc->sc_pcitag, PIIX_PM_BASE, pmbase);
+
+	pci_conf_write(sc->sc_pc, sc->sc_pcitag, PIIX_SMB_BASE, base);
+	pci_conf_write(sc->sc_pc, sc->sc_pcitag, PIIX_SMB_HOSTC, hostc);
+
+	(void) tsleep(&sc, PRIBIO, "csb5reset", hz/2);
+}
+
 static int
 piixpm_i2c_acquire_bus(void *cookie, int flags)
 {
@@ -372,7 +399,10 @@
 
 	if (flags & I2C_F_POLL) {
 		/* Poll for completion */
-		DELAY(PIIXPM_DELAY);
+		if (PIIXPM_IS_CSB5(sc->sc_id))
+			DELAY(2*PIIXPM_DELAY);
+		else
+			DELAY(PIIXPM_DELAY);
 		for (retries = 1000; retries > 0; retries--) {
 			st = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh,
 			    PIIX_SMB_HS);
@@ -406,6 +436,11 @@
 	if ((st & PIIX_SMB_HS_FAILED) == 0)
 		aprint_error_dev(sc->sc_dev, "transaction abort failed, status 0x%x\n", st);
 	bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_HS, st);
+	/*
+	 * CSB5 needs hard reset to unlock the smbus after timeout.
+	 */
+	if (PIIXPM_IS_CSB5(sc->sc_id))
+		piixpm_csb5_reset(sc);
 	return (1);
 }
 

Index: src/sys/dev/pci/piixpmreg.h
diff -u src/sys/dev/pci/piixpmreg.h:1.4 src/sys/dev/pci/piixpmreg.h:1.5
--- src/sys/dev/pci/piixpmreg.h:1.4	Mon Jun 26 17:33:40 2006
+++ src/sys/dev/pci/piixpmreg.h	Sun Feb 13 11:20:12 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: piixpmreg.h,v 1.4 2006/06/26 17:33:40 drochner Exp $ */
+/* $NetBSD: piixpmreg.h,v 1.5 2011/02/13 11:20:12 hannken Exp $ */
 /*	$OpenBSD: piixreg.h,v 1.3 2006/01/03 22:39:03 grange Exp $	*/
 
 /*
@@ -30,6 +30,7 @@
 
 /* PCI configuration registers */
 #define PIIX_PM_BASE	0x40		/* Power management base address */
+#define PIIX_PM_BASE_CSB5_RESET	0x10		/* CSB5 PM reset */
 #define PIIX_DEVACTA	0x54		/* Device activity A (function 3) */
 #define PIIX_DEVACTB	0x58		/* Device activity B (function 3) */
 #define PIIX_PMREGMISC	0x80		/* Misc. Power management */

Reply via email to