Author: wulf
Date: Sun Nov  3 20:53:13 2019
New Revision: 354302
URL: https://svnweb.freebsd.org/changeset/base/354302

Log:
  [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.

Modified:
  head/sys/dev/ichiic/ig4_acpi.c
  head/sys/dev/ichiic/ig4_iic.c
  head/sys/dev/ichiic/ig4_pci.c
  head/sys/dev/ichiic/ig4_var.h

Modified: head/sys/dev/ichiic/ig4_acpi.c
==============================================================================
--- head/sys/dev/ichiic/ig4_acpi.c      Sun Nov  3 20:51:22 2019        
(r354301)
+++ head/sys/dev/ichiic/ig4_acpi.c      Sun Nov  3 20:53:13 2019        
(r354302)
@@ -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
 };

Modified: head/sys/dev/ichiic/ig4_iic.c
==============================================================================
--- head/sys/dev/ichiic/ig4_iic.c       Sun Nov  3 20:51:22 2019        
(r354301)
+++ head/sys/dev/ichiic/ig4_iic.c       Sun Nov  3 20:53:13 2019        
(r354302)
@@ -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, ui
        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, ui
                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, ui
                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,8 +484,41 @@ ig4iic_reset(device_t dev, u_char speed, u_char addr, 
        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);
 }
 
 /*

Modified: head/sys/dev/ichiic/ig4_pci.c
==============================================================================
--- head/sys/dev/ichiic/ig4_pci.c       Sun Nov  3 20:51:22 2019        
(r354301)
+++ head/sys/dev/ichiic/ig4_pci.c       Sun Nov  3 20:53:13 2019        
(r354302)
@@ -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
 };

Modified: head/sys/dev/ichiic/ig4_var.h
==============================================================================
--- head/sys/dev/ichiic/ig4_var.h       Sun Nov  3 20:51:22 2019        
(r354301)
+++ head/sys/dev/ichiic/ig4_var.h       Sun Nov  3 20:53:13 2019        
(r354302)
@@ -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_ */
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to