Page MenuHomeFreeBSD

D2744.diff
No OneTemporary

D2744.diff

Index: head/sys/dev/ichiic/ig4_iic.c
===================================================================
--- head/sys/dev/ichiic/ig4_iic.c
+++ head/sys/dev/ichiic/ig4_iic.c
@@ -40,6 +40,7 @@
* Intel fourth generation mobile cpus integrated I2C device, smbus driver.
*
* See ig4_reg.h for datasheet reference and notes.
+ * See ig4_var.h for locking semantics.
*/
#include <sys/param.h>
@@ -49,6 +50,7 @@
#include <sys/errno.h>
#include <sys/lock.h>
#include <sys/mutex.h>
+#include <sys/sx.h>
#include <sys/syslog.h>
#include <sys/bus.h>
#include <sys/sysctl.h>
@@ -115,7 +117,7 @@
error = 0;
break;
}
- mtx_sleep(sc, &sc->mutex, 0, "i2cslv", 1);
+ mtx_sleep(sc, &sc->io_lock, 0, "i2cslv", 1);
}
return (error);
}
@@ -179,7 +181,7 @@
* work, otherwise poll with the lock held.
*/
if (status & IG4_STATUS_RX_NOTEMPTY) {
- mtx_sleep(sc, &sc->mutex, PZERO, "i2cwait",
+ mtx_sleep(sc, &sc->io_lock, 0, "i2cwait",
(hz + 99) / 100); /* sleep up to 10ms */
count_us += 10000;
} else {
@@ -522,6 +524,8 @@
* Use a threshold of 1 so we get interrupted on each character,
* allowing us to use mtx_sleep() in our poll code. Not perfect
* but this is better than using DELAY() for receiving data.
+ *
+ * See ig4_var.h for details on interrupt handler synchronization.
*/
reg_write(sc, IG4_REG_RX_TL, 1);
@@ -551,12 +555,12 @@
*/
reg_write(sc, IG4_REG_INTR_MASK, IG4_INTR_STOP_DET |
IG4_INTR_RX_FULL);
- mtx_lock(&sc->mutex);
+ mtx_lock(&sc->io_lock);
if (set_controller(sc, 0))
device_printf(sc->dev, "controller error during attach-1\n");
if (set_controller(sc, IG4_I2C_ENABLE))
device_printf(sc->dev, "controller error during attach-2\n");
- mtx_unlock(&sc->mutex);
+ mtx_unlock(&sc->io_lock);
error = bus_setup_intr(sc->dev, sc->intr_res, INTR_TYPE_MISC | INTR_MPSAFE,
NULL, ig4iic_intr, sc, &sc->intr_handle);
if (error) {
@@ -615,7 +619,8 @@
if (sc->intr_handle)
bus_teardown_intr(sc->dev, sc->intr_res, sc->intr_handle);
- mtx_lock(&sc->mutex);
+ sx_xlock(&sc->call_lock);
+ mtx_lock(&sc->io_lock);
sc->smb = NULL;
sc->intr_handle = NULL;
@@ -623,18 +628,16 @@
reg_read(sc, IG4_REG_CLR_INTR);
set_controller(sc, 0);
- mtx_unlock(&sc->mutex);
+ mtx_unlock(&sc->io_lock);
+ sx_xunlock(&sc->call_lock);
return (0);
}
int
ig4iic_smb_callback(device_t dev, int index, void *data)
{
- ig4iic_softc_t *sc = device_get_softc(dev);
int error;
- mtx_lock(&sc->mutex);
-
switch (index) {
case SMB_REQUEST_BUS:
error = 0;
@@ -647,8 +650,6 @@
break;
}
- mtx_unlock(&sc->mutex);
-
return (error);
}
@@ -660,25 +661,8 @@
int
ig4iic_smb_quick(device_t dev, u_char slave, int how)
{
- ig4iic_softc_t *sc = device_get_softc(dev);
- int error;
-
- mtx_lock(&sc->mutex);
- switch (how) {
- case SMB_QREAD:
- error = SMB_ENOTSUPP;
- break;
- case SMB_QWRITE:
- error = SMB_ENOTSUPP;
- break;
- default:
- error = SMB_ENOTSUPP;
- break;
- }
- mtx_unlock(&sc->mutex);
-
- return (error);
+ return (SMB_ENOTSUPP);
}
/*
@@ -695,7 +679,8 @@
uint32_t cmd;
int error;
- mtx_lock(&sc->mutex);
+ sx_xlock(&sc->call_lock);
+ mtx_lock(&sc->io_lock);
set_slave_addr(sc, slave, 0);
cmd = byte;
@@ -706,7 +691,8 @@
error = SMB_ETIMEOUT;
}
- mtx_unlock(&sc->mutex);
+ mtx_unlock(&sc->io_lock);
+ sx_xunlock(&sc->call_lock);
return (error);
}
@@ -721,7 +707,8 @@
ig4iic_softc_t *sc = device_get_softc(dev);
int error;
- mtx_lock(&sc->mutex);
+ sx_xlock(&sc->call_lock);
+ mtx_lock(&sc->io_lock);
set_slave_addr(sc, slave, 0);
reg_write(sc, IG4_REG_DATA_CMD, IG4_DATA_COMMAND_RD);
@@ -733,7 +720,8 @@
error = SMB_ETIMEOUT;
}
- mtx_unlock(&sc->mutex);
+ mtx_unlock(&sc->io_lock);
+ sx_xunlock(&sc->call_lock);
return (error);
}
@@ -746,13 +734,15 @@
ig4iic_softc_t *sc = device_get_softc(dev);
int error;
- mtx_lock(&sc->mutex);
+ sx_xlock(&sc->call_lock);
+ mtx_lock(&sc->io_lock);
set_slave_addr(sc, slave, 0);
error = smb_transaction(sc, cmd, SMB_TRANS_NOCNT,
&byte, 1, NULL, 0, NULL);
- mtx_unlock(&sc->mutex);
+ mtx_unlock(&sc->io_lock);
+ sx_xunlock(&sc->call_lock);
return (error);
}
@@ -766,7 +756,8 @@
char buf[2];
int error;
- mtx_lock(&sc->mutex);
+ sx_xlock(&sc->call_lock);
+ mtx_lock(&sc->io_lock);
set_slave_addr(sc, slave, 0);
buf[0] = word & 0xFF;
@@ -774,7 +765,8 @@
error = smb_transaction(sc, cmd, SMB_TRANS_NOCNT,
buf, 2, NULL, 0, NULL);
- mtx_unlock(&sc->mutex);
+ mtx_unlock(&sc->io_lock);
+ sx_xunlock(&sc->call_lock);
return (error);
}
@@ -787,13 +779,15 @@
ig4iic_softc_t *sc = device_get_softc(dev);
int error;
- mtx_lock(&sc->mutex);
+ sx_xlock(&sc->call_lock);
+ mtx_lock(&sc->io_lock);
set_slave_addr(sc, slave, 0);
error = smb_transaction(sc, cmd, SMB_TRANS_NOCNT,
NULL, 0, byte, 1, NULL);
- mtx_unlock(&sc->mutex);
+ mtx_unlock(&sc->io_lock);
+ sx_xunlock(&sc->call_lock);
return (error);
}
@@ -807,7 +801,8 @@
char buf[2];
int error;
- mtx_lock(&sc->mutex);
+ sx_xlock(&sc->call_lock);
+ mtx_lock(&sc->io_lock);
set_slave_addr(sc, slave, 0);
if ((error = smb_transaction(sc, cmd, SMB_TRANS_NOCNT,
@@ -815,7 +810,8 @@
*word = (u_char)buf[0] | ((u_char)buf[1] << 8);
}
- mtx_unlock(&sc->mutex);
+ mtx_unlock(&sc->io_lock);
+ sx_xunlock(&sc->call_lock);
return (error);
}
@@ -831,7 +827,8 @@
char wbuf[2];
int error;
- mtx_lock(&sc->mutex);
+ sx_xlock(&sc->call_lock);
+ mtx_lock(&sc->io_lock);
set_slave_addr(sc, slave, 0);
wbuf[0] = sdata & 0xFF;
@@ -841,7 +838,8 @@
*rdata = (u_char)rbuf[0] | ((u_char)rbuf[1] << 8);
}
- mtx_unlock(&sc->mutex);
+ mtx_unlock(&sc->io_lock);
+ sx_xunlock(&sc->call_lock);
return (error);
}
@@ -852,13 +850,15 @@
ig4iic_softc_t *sc = device_get_softc(dev);
int error;
- mtx_lock(&sc->mutex);
+ sx_xlock(&sc->call_lock);
+ mtx_lock(&sc->io_lock);
set_slave_addr(sc, slave, 0);
error = smb_transaction(sc, cmd, 0,
buf, wcount, NULL, 0, NULL);
- mtx_unlock(&sc->mutex);
+ mtx_unlock(&sc->io_lock);
+ sx_xunlock(&sc->call_lock);
return (error);
}
@@ -870,14 +870,16 @@
int rcount = *countp_char;
int error;
- mtx_lock(&sc->mutex);
+ sx_xlock(&sc->call_lock);
+ mtx_lock(&sc->io_lock);
set_slave_addr(sc, slave, 0);
error = smb_transaction(sc, cmd, 0,
NULL, 0, buf, rcount, &rcount);
*countp_char = rcount;
- mtx_unlock(&sc->mutex);
+ mtx_unlock(&sc->io_lock);
+ sx_xunlock(&sc->call_lock);
return (error);
}
@@ -889,18 +891,20 @@
ig4iic_softc_t *sc = device_get_softc(dev);
int error;
- mtx_lock(&sc->mutex);
+ sx_xlock(&sc->call_lock);
+ mtx_lock(&sc->io_lock);
set_slave_addr(sc, slave, op);
error = smb_transaction(sc, cmd, op,
wbuf, wcount, rbuf, rcount, actualp);
- mtx_unlock(&sc->mutex);
+ mtx_unlock(&sc->io_lock);
+ sx_xunlock(&sc->call_lock);
return (error);
}
/*
- * Interrupt Operation
+ * Interrupt Operation, see ig4_var.h for locking semantics.
*/
static void
ig4iic_intr(void *cookie)
@@ -908,7 +912,7 @@
ig4iic_softc_t *sc = cookie;
uint32_t status;
- mtx_lock(&sc->mutex);
+ mtx_lock(&sc->io_lock);
/* reg_write(sc, IG4_REG_INTR_MASK, IG4_INTR_STOP_DET);*/
status = reg_read(sc, IG4_REG_I2C_STA);
while (status & IG4_STATUS_RX_NOTEMPTY) {
@@ -919,7 +923,7 @@
}
reg_read(sc, IG4_REG_CLR_INTR);
wakeup(sc);
- mtx_unlock(&sc->mutex);
+ mtx_unlock(&sc->io_lock);
}
#define REGDUMP(sc, reg) \
Index: head/sys/dev/ichiic/ig4_pci.c
===================================================================
--- head/sys/dev/ichiic/ig4_pci.c
+++ head/sys/dev/ichiic/ig4_pci.c
@@ -49,6 +49,7 @@
#include <sys/errno.h>
#include <sys/lock.h>
#include <sys/mutex.h>
+#include <sys/sx.h>
#include <sys/syslog.h>
#include <sys/bus.h>
@@ -94,7 +95,8 @@
bzero(sc, sizeof(*sc));
- mtx_init(&sc->mutex, device_get_nameunit(dev), "ig4iic", MTX_DEF);
+ mtx_init(&sc->io_lock, "IG4 I/O lock", NULL, MTX_DEF);
+ sx_init(&sc->call_lock, "IG4 call lock");
sc->dev = dev;
sc->regs_rid = PCIR_BAR(0);
@@ -150,7 +152,10 @@
sc->regs_rid, sc->regs_res);
sc->regs_res = NULL;
}
- mtx_destroy(&sc->mutex);
+ if (mtx_initialized(&sc->io_lock)) {
+ mtx_destroy(&sc->io_lock);
+ sx_destroy(&sc->call_lock);
+ }
return (0);
}
@@ -179,9 +184,9 @@
};
static driver_t ig4iic_pci_driver = {
- "ig4iic",
- ig4iic_pci_methods,
- sizeof(struct ig4iic_softc)
+ "ig4iic",
+ ig4iic_pci_methods,
+ sizeof(struct ig4iic_softc)
};
static devclass_t ig4iic_pci_devclass;
Index: head/sys/dev/ichiic/ig4_var.h
===================================================================
--- head/sys/dev/ichiic/ig4_var.h
+++ head/sys/dev/ichiic/ig4_var.h
@@ -70,7 +70,30 @@
int slave_valid : 1;
int read_started : 1;
int write_started : 1;
- struct mtx mutex;
+
+ /*
+ * Locking semantics:
+ *
+ * Functions implementing the smbus interface that interact
+ * with the controller acquire an exclusive lock on call_lock
+ * to prevent interleaving of calls to the interface and a lock on
+ * io_lock right afterwards, to synchronize controller I/O activity.
+ *
+ * The interrupt handler can only read data while no ig4iic_smb_* call
+ * is in progress or while io_lock is dropped during mtx_sleep in
+ * wait_status and set_controller. It is safe to drop io_lock in those
+ * places, because the interrupt handler only accesses those registers:
+ *
+ * - IG4_REG_I2C_STA (I2C Status)
+ * - IG4_REG_DATA_CMD (Data Buffer and Command)
+ * - IG4_REG_CLR_INTR (Clear Interrupt)
+ *
+ * Locking outside of those places is required to make the content
+ * of rpos/rnext predictable (e.g. whenever data_read is called and in
+ * smb_transaction).
+ */
+ struct sx call_lock;
+ struct mtx io_lock;
};
typedef struct ig4iic_softc ig4iic_softc_t;

File Metadata

Mime Type
text/plain
Expires
Sat, Dec 21, 4:34 PM (19 h, 50 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
15543328
Default Alt Text
D2744.diff (9 KB)

Event Timeline