[ig4] Allow enabling of polled mode from iicbus allocation callback

If controller is allocated with IIC_NOWAIT option ig4 enables polled mode
for a period of allocation that makes possible to start I2C transfers
from the contexts where sleeping is not allowed e.g. from ithreads or
callouts.
This commit is contained in:
Vladimir Kondratyev 2019-11-03 20:53:13 +00:00
parent c59aca578e
commit 41b24e0917
4 changed files with 50 additions and 7 deletions

View File

@ -154,7 +154,7 @@ static device_method_t ig4iic_acpi_methods[] = {
/* iicbus interface */
DEVMETHOD(iicbus_transfer, ig4iic_transfer),
DEVMETHOD(iicbus_reset, ig4iic_reset),
DEVMETHOD(iicbus_callback, iicbus_null_callback),
DEVMETHOD(iicbus_callback, ig4iic_callback),
DEVMETHOD_END
};

View File

@ -72,7 +72,7 @@ __FBSDID("$FreeBSD$");
#define TRANS_PCALL 2
#define TRANS_BLOCK 3
#define DO_POLL(sc) (cold || kdb_active || SCHEDULER_STOPPED())
#define DO_POLL(sc) (cold || kdb_active || SCHEDULER_STOPPED() || sc->poll)
static void ig4iic_start(void *xdev);
static void ig4iic_intr(void *cookie);
@ -350,6 +350,7 @@ ig4iic_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs)
int unit;
bool rpstart;
bool stop;
bool allocated;
/*
* The hardware interface imposes limits on allowed I2C messages.
@ -410,7 +411,10 @@ ig4iic_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs)
return (IIC_ENOTSUPP);
}
sx_xlock(&sc->call_lock);
/* Check if device is already allocated with iicbus_request_bus() */
allocated = sx_xlocked(&sc->call_lock) != 0;
if (!allocated)
sx_xlock(&sc->call_lock);
/* Debugging - dump registers. */
if (ig4_dump) {
@ -458,7 +462,8 @@ ig4iic_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs)
rpstart = !stop;
}
sx_unlock(&sc->call_lock);
if (!allocated)
sx_unlock(&sc->call_lock);
return (error);
}
@ -466,8 +471,11 @@ int
ig4iic_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
{
ig4iic_softc_t *sc = device_get_softc(dev);
bool allocated;
sx_xlock(&sc->call_lock);
allocated = sx_xlocked(&sc->call_lock) != 0;
if (!allocated)
sx_xlock(&sc->call_lock);
/* TODO handle speed configuration? */
if (oldaddr != NULL)
@ -476,10 +484,43 @@ ig4iic_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
if (addr == IIC_UNKNOWN)
sc->slave_valid = false;
sx_unlock(&sc->call_lock);
if (!allocated)
sx_unlock(&sc->call_lock);
return (0);
}
int
ig4iic_callback(device_t dev, int index, caddr_t data)
{
ig4iic_softc_t *sc = device_get_softc(dev);
int error = 0;
int how;
switch (index) {
case IIC_REQUEST_BUS:
/* force polling if ig4iic is requested with IIC_DONTWAIT */
how = *(int *)data;
if ((how & IIC_WAIT) == 0) {
if (sx_try_xlock(&sc->call_lock) == 0)
error = IIC_EBUSBSY;
else
sc->poll = true;
} else
sx_xlock(&sc->call_lock);
break;
case IIC_RELEASE_BUS:
sc->poll = false;
sx_unlock(&sc->call_lock);
break;
default:
error = errno2iic(EINVAL);
}
return (error);
}
/*
* Called from ig4iic_pci_attach/detach()
*/

View File

@ -214,7 +214,7 @@ static device_method_t ig4iic_pci_methods[] = {
DEVMETHOD(iicbus_transfer, ig4iic_transfer),
DEVMETHOD(iicbus_reset, ig4iic_reset),
DEVMETHOD(iicbus_callback, iicbus_null_callback),
DEVMETHOD(iicbus_callback, ig4iic_callback),
DEVMETHOD_END
};

View File

@ -67,6 +67,7 @@ struct ig4iic_softc {
int slave_valid : 1;
int read_started : 1;
int write_started : 1;
int poll: 1;
/*
* Locking semantics:
@ -95,5 +96,6 @@ int ig4iic_detach(ig4iic_softc_t *sc);
/* iicbus methods */
extern iicbus_transfer_t ig4iic_transfer;
extern iicbus_reset_t ig4iic_reset;
extern iicbus_callback_t ig4iic_callback;
#endif /* _ICHIIC_IG4_VAR_H_ */