Source-Changes-HG archive

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

[src/trunk]: src/sys/dev/pci Make ichsmb and piixpm MP-safe:



details:   https://anonhg.NetBSD.org/src/rev/1e804061b80c
branches:  trunk
changeset: 967857:1e804061b80c
user:      thorpej <thorpej%NetBSD.org@localhost>
date:      Tue Dec 24 06:27:17 2019 +0000

description:
Make ichsmb and piixpm MP-safe:
- Synchronize with the interrupt handler using a mutex.
- Use a condvar to wait for completion, rather than tsleep().
- Mark our interrupt handler as such.

Also, other general correctness fixes:
- Loop around testing the completion condition to protect aginst
  spurious wakes.
- The "i2c exec" function returns an error code, so actually do so.

diffstat:

 sys/dev/pci/ichsmb.c |  62 ++++++++++++++++++++++++++++++++++++++-------------
 sys/dev/pci/piixpm.c |  59 ++++++++++++++++++++++++++++++++++++-------------
 2 files changed, 89 insertions(+), 32 deletions(-)

diffs (truncated from 345 to 300 lines):

diff -r b3c92b78703f -r 1e804061b80c sys/dev/pci/ichsmb.c
--- a/sys/dev/pci/ichsmb.c      Tue Dec 24 05:00:19 2019 +0000
+++ b/sys/dev/pci/ichsmb.c      Tue Dec 24 06:27:17 2019 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ichsmb.c,v 1.64 2019/12/23 15:34:40 thorpej Exp $      */
+/*     $NetBSD: ichsmb.c,v 1.65 2019/12/24 06:27:17 thorpej Exp $      */
 /*     $OpenBSD: ichiic.c,v 1.18 2007/05/03 09:36:26 dlg Exp $ */
 
 /*
@@ -22,13 +22,14 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ichsmb.c,v 1.64 2019/12/23 15:34:40 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ichsmb.c,v 1.65 2019/12/24 06:27:17 thorpej Exp $");
 
 #include <sys/param.h>
 #include <sys/device.h>
 #include <sys/errno.h>
 #include <sys/kernel.h>
 #include <sys/mutex.h>
+#include <sys/condvar.h>
 #include <sys/proc.h>
 #include <sys/module.h>
 
@@ -62,13 +63,17 @@
        int                     sc_poll;
        pci_intr_handle_t       *sc_pihp;
 
+       kmutex_t                sc_exec_lock;
+       kcondvar_t              sc_exec_wait;
+
        struct i2c_controller   sc_i2c_tag;
        struct {
                i2c_op_t     op;
                void *       buf;
                size_t       len;
                int          flags;
-               volatile int error;
+               int          error;
+               bool         done;
        }                       sc_i2c_xfer;
        device_t                sc_i2c_device;
 };
@@ -161,6 +166,9 @@
 
        pci_aprint_devinfo(pa, NULL);
 
+       mutex_init(&sc->sc_exec_lock, MUTEX_DEFAULT, IPL_BIO);
+       cv_init(&sc->sc_exec_wait, device_xname(self));
+
        /* Read configuration */
        conf = pci_conf_read(pa->pa_pc, pa->pa_tag, LPCIB_SMB_HOSTC);
        DPRINTF(("%s: conf 0x%08x\n", device_xname(sc->sc_dev), conf));
@@ -187,6 +195,8 @@
                if (pci_intr_alloc(pa, &sc->sc_pihp, NULL, 0) == 0) {
                        intrstr = pci_intr_string(pa->pa_pc, sc->sc_pihp[0],
                            intrbuf, sizeof(intrbuf));
+                       pci_intr_setattr(pa->pa_pc, &sc->sc_pihp[0],
+                           PCI_INTR_MPSAFE, true);
                        sc->sc_ih = pci_intr_establish_xname(pa->pa_pc,
                            sc->sc_pihp[0], IPL_BIO, ichsmb_intr, sc,
                            device_xname(sc->sc_dev));
@@ -262,6 +272,9 @@
        if (sc->sc_size != 0)
                bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_size);
 
+       mutex_destroy(&sc->sc_exec_lock);
+       cv_destroy(&sc->sc_exec_wait);
+
        return 0;
 }
 
@@ -288,6 +301,8 @@
            "flags 0x%02x\n", device_xname(sc->sc_dev), op, addr, cmdlen,
            len, flags));
 
+       mutex_enter(&sc->sc_exec_lock);
+
        /* Clear status bits */
        bus_space_write_1(sc->sc_iot, sc->sc_ioh, LPCIB_SMB_HS,
            LPCIB_SMB_HS_INTR | LPCIB_SMB_HS_DEVERR |
@@ -306,15 +321,19 @@
        snprintb(fbuf, sizeof(fbuf), LPCIB_SMB_HS_BITS, st);
        printf("%s: exec: st %s\n", device_xname(sc->sc_dev), fbuf);
 #endif
-       if (st & LPCIB_SMB_HS_BUSY)
-               return (1);
+       if (st & LPCIB_SMB_HS_BUSY) {
+               mutex_exit(&sc->sc_exec_lock);
+               return (EBUSY);
+       }
 
        if (sc->sc_poll)
                flags |= I2C_F_POLL;
 
        if (!I2C_OP_STOP_P(op) || cmdlen > 1 || len > 2 ||
-           (cmdlen == 0 && len > 1))
-               return (1);
+           (cmdlen == 0 && len > 1)) {
+               mutex_exit(&sc->sc_exec_lock);
+               return (EINVAL);
+       }
 
        /* Setup transfer */
        sc->sc_i2c_xfer.op = op;
@@ -322,6 +341,7 @@
        sc->sc_i2c_xfer.len = len;
        sc->sc_i2c_xfer.flags = flags;
        sc->sc_i2c_xfer.error = 0;
+       sc->sc_i2c_xfer.done = false;
 
        /* Set slave address and transfer direction */
        bus_space_write_1(sc->sc_iot, sc->sc_ioh, LPCIB_SMB_TXSLVA,
@@ -380,14 +400,17 @@
                ichsmb_intr(sc);
        } else {
                /* Wait for interrupt */
-               if (tsleep(sc, PRIBIO, "iicexec", ICHIIC_TIMEOUT * hz))
-                       goto timeout;
+               while (! sc->sc_i2c_xfer.done) {
+                       if (cv_timedwait(&sc->sc_exec_wait, &sc->sc_exec_lock,
+                                        ICHIIC_TIMEOUT * hz))
+                               goto timeout;
+               }
        }
 
-       if (sc->sc_i2c_xfer.error)
-               return (1);
+       int error = sc->sc_i2c_xfer.error;
+       mutex_exit(&sc->sc_exec_lock);
 
-       return (0);
+       return (error);
 
 timeout:
        /*
@@ -408,7 +431,8 @@
                    fbuf);
        }
        bus_space_write_1(sc->sc_iot, sc->sc_ioh, LPCIB_SMB_HS, st);
-       return (1);
+       mutex_exit(&sc->sc_exec_lock);
+       return (ETIMEDOUT);
 }
 
 static int
@@ -435,12 +459,15 @@
        printf("%s: intr st %s\n", device_xname(sc->sc_dev), fbuf);
 #endif
 
+       if ((sc->sc_i2c_xfer.flags & I2C_F_POLL) == 0)
+               mutex_enter(&sc->sc_exec_lock);
+
        /* Clear status bits */
        bus_space_write_1(sc->sc_iot, sc->sc_ioh, LPCIB_SMB_HS, st);
 
        /* Check for errors */
        if (st & (LPCIB_SMB_HS_DEVERR | LPCIB_SMB_HS_BUSERR | LPCIB_SMB_HS_FAILED)) {
-               sc->sc_i2c_xfer.error = 1;
+               sc->sc_i2c_xfer.error = EIO;
                goto done;
        }
 
@@ -460,8 +487,11 @@
        }
 
 done:
-       if ((sc->sc_i2c_xfer.flags & I2C_F_POLL) == 0)
-               wakeup(sc);
+       sc->sc_i2c_xfer.done = true;
+       if ((sc->sc_i2c_xfer.flags & I2C_F_POLL) == 0) {
+               cv_signal(&sc->sc_exec_wait);
+               mutex_exit(&sc->sc_exec_lock);
+       }
        return (1);
 }
 
diff -r b3c92b78703f -r 1e804061b80c sys/dev/pci/piixpm.c
--- a/sys/dev/pci/piixpm.c      Tue Dec 24 05:00:19 2019 +0000
+++ b/sys/dev/pci/piixpm.c      Tue Dec 24 06:27:17 2019 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: piixpm.c,v 1.59 2019/12/24 03:43:34 msaitoh Exp $ */
+/* $NetBSD: piixpm.c,v 1.60 2019/12/24 06:27:17 thorpej Exp $ */
 /*     $OpenBSD: piixpm.c,v 1.39 2013/10/01 20:06:02 sf Exp $  */
 
 /*
@@ -22,13 +22,14 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: piixpm.c,v 1.59 2019/12/24 03:43:34 msaitoh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: piixpm.c,v 1.60 2019/12/24 06:27:17 thorpej Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/device.h>
 #include <sys/kernel.h>
 #include <sys/mutex.h>
+#include <sys/condvar.h>
 #include <sys/proc.h>
 
 #include <sys/bus.h>
@@ -98,12 +99,16 @@
        struct piixpm_smbus     sc_busses[4];
        struct i2c_controller   sc_i2c_tags[4];
 
+       kmutex_t                sc_exec_lock;
+       kcondvar_t              sc_exec_wait;
+
        struct {
                i2c_op_t        op;
                void *          buf;
                size_t          len;
                int             flags;
-               volatile int    error;
+               int             error;
+               bool            done;
        }                       sc_i2c_xfer;
 
        pcireg_t                sc_devact[2];
@@ -197,6 +202,9 @@
 
        pci_aprint_devinfo(pa, NULL);
 
+       mutex_init(&sc->sc_exec_lock, MUTEX_DEFAULT, IPL_BIO);
+       cv_init(&sc->sc_exec_wait, device_xname(self));
+
        if (!pmf_device_register(self, piixpm_suspend, piixpm_resume))
                aprint_error_dev(self, "couldn't establish power handler\n");
 
@@ -272,6 +280,8 @@
                        if (pci_intr_map(pa, &ih) == 0) {
                                intrstr = pci_intr_string(pa->pa_pc, ih,
                                    intrbuf, sizeof(intrbuf));
+                               pci_intr_setattr(pa->pa_pc, &ih,
+                                   PCI_INTR_MPSAFE, true);
                                sc->sc_smb_ih = pci_intr_establish_xname(
                                        pa->pa_pc, ih, IPL_BIO, piixpm_intr,
                                        sc, device_xname(sc->sc_dev));
@@ -557,6 +567,8 @@
                "flags 0x%x\n",
                device_xname(sc->sc_dev), op, addr, cmdlen, len, flags));
 
+       mutex_enter(&sc->sc_exec_lock);
+
        /* Clear status bits */
        bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_HS,
            PIIX_SMB_HS_INTR | PIIX_SMB_HS_DEVERR |
@@ -573,15 +585,19 @@
                DELAY(PIIXPM_DELAY);
        }
        DPRINTF(("%s: exec: st %#x\n", device_xname(sc->sc_dev), st & 0xff));
-       if (st & PIIX_SMB_HS_BUSY)
-               return (1);
+       if (st & PIIX_SMB_HS_BUSY) {
+               mutex_exit(&sc->sc_exec_lock);
+               return (EBUSY);
+       }
 
        if (sc->sc_poll)
                flags |= I2C_F_POLL;
 
        if (!I2C_OP_STOP_P(op) || cmdlen > 1 || len > 2 ||
-           (cmdlen == 0 && len > 1))
-               return (1);
+           (cmdlen == 0 && len > 1)) {
+               mutex_exit(&sc->sc_exec_lock);
+               return (EINVAL);
+       }
 
        /* Setup transfer */
        sc->sc_i2c_xfer.op = op;
@@ -589,6 +605,7 @@
        sc->sc_i2c_xfer.len = len;
        sc->sc_i2c_xfer.flags = flags;
        sc->sc_i2c_xfer.error = 0;
+       sc->sc_i2c_xfer.done = false;
 
        /* Set slave address and transfer direction */
        bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_TXSLVA,
@@ -653,14 +670,17 @@
                piixpm_intr(sc);
        } else {
                /* Wait for interrupt */
-               if (tsleep(sc, PRIBIO, "piixpm", PIIXPM_TIMEOUT * hz))
-                       goto timeout;
+               while (! sc->sc_i2c_xfer.done) {
+                       if (cv_timedwait(&sc->sc_exec_wait, &sc->sc_exec_lock,
+                                        PIIXPM_TIMEOUT * hz))
+                               goto timeout;
+               }
        }
 
-       if (sc->sc_i2c_xfer.error)
-               return (1);
+       int error = sc->sc_i2c_xfer.error;
+       mutex_exit(&sc->sc_exec_lock);
 
-       return (0);



Home | Main Index | Thread Index | Old Index