Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/pci The ServerWorks CSB5 smbus controller often time...



details:   https://anonhg.NetBSD.org/src/rev/f423c31ab419
branches:  trunk
changeset: 762021:f423c31ab419
user:      hannken <hannken%NetBSD.org@localhost>
date:      Sun Feb 13 11:20:12 2011 +0000

description:
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.

diffstat:

 sys/dev/pci/piixpm.c    |  41 ++++++++++++++++++++++++++++++++++++++---
 sys/dev/pci/piixpmreg.h |   3 ++-
 2 files changed, 40 insertions(+), 4 deletions(-)

diffs (121 lines):

diff -r 4a77220006f4 -r f423c31ab419 sys/dev/pci/piixpm.c
--- a/sys/dev/pci/piixpm.c      Sun Feb 13 11:00:58 2011 +0000
+++ b/sys/dev/pci/piixpm.c      Sun Feb 13 11:20:12 2011 +0000
@@ -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);
 }
 
diff -r 4a77220006f4 -r f423c31ab419 sys/dev/pci/piixpmreg.h
--- a/sys/dev/pci/piixpmreg.h   Sun Feb 13 11:00:58 2011 +0000
+++ b/sys/dev/pci/piixpmreg.h   Sun Feb 13 11:20:12 2011 +0000
@@ -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 */



Home | Main Index | Thread Index | Old Index