Removed some locks causing latency when using the library; added ioctl()
authorFlorian Pose <fp@igh-essen.com>
Tue, 20 Dec 2011 11:12:04 +0100
changeset 2182 4dc680830349
parent 2181 cac59f7a42c4
child 2183 b784af1203a4
Removed some locks causing latency when using the library; added ioctl()
latency debugging; fixed FoE memory leaks in error case.
master/cdev.c
--- a/master/cdev.c	Fri Dec 16 16:26:16 2011 +0100
+++ b/master/cdev.c	Tue Dec 20 11:12:04 2011 +0100
@@ -49,6 +49,12 @@
  */
 #define DEBUG_IOCTL 0
 
+/** Set to 1 to enable ioctl() latency warnings.
+ *
+ * Requires CPU timestamp counter!
+ */
+#define DEBUG_LATENCY 0
+
 /*****************************************************************************/
 
 static int eccdev_open(struct inode *, struct file *);
@@ -1724,12 +1730,12 @@
 
     if (ec_mutex_lock_interruptible(&master->master_mutex))
         return -EINTR;
+
     ec_master_set_send_interval(master, send_interval);
+
     ec_mutex_unlock(&master->master_mutex);
-
-    return 0;
-}
-
+    return 0;
+}
 
 /*****************************************************************************/
 
@@ -2104,7 +2110,8 @@
         return -ENOENT;
     }
 
-    ec_mutex_unlock(&master->master_mutex); // FIXME
+    ec_mutex_unlock(&master->master_mutex); /** \fixme sc could be invalidated
+                                             */
 
     return ecrt_slave_config_pdo_assign_add(sc, data.sync_index, data.index);
 }
@@ -2136,7 +2143,8 @@
         return -ENOENT;
     }
 
-    ec_mutex_unlock(&master->master_mutex); // FIXME
+    ec_mutex_unlock(&master->master_mutex); /** \fixme sc could be invalidated
+                                             */
 
     ecrt_slave_config_pdo_assign_clear(sc, data.sync_index);
     return 0;
@@ -2169,7 +2177,8 @@
         return -ENOENT;
     }
 
-    ec_mutex_unlock(&master->master_mutex); // FIXME
+    ec_mutex_unlock(&master->master_mutex); /** \fixme sc could be invalidated
+                                             */
 
     return ecrt_slave_config_pdo_mapping_add(sc, data.pdo_index,
             data.entry_index, data.entry_subindex, data.entry_bit_length);
@@ -2202,7 +2211,8 @@
         return -ENOENT;
     }
 
-    ec_mutex_unlock(&master->master_mutex); // FIXME
+    ec_mutex_unlock(&master->master_mutex); /** \fixme sc could be invalidated
+                                             */
 
     ecrt_slave_config_pdo_mapping_clear(sc, data.index);
     return 0;
@@ -2242,7 +2252,8 @@
         return -ENOENT;
     }
 
-    ec_mutex_unlock(&master->master_mutex); // FIXME
+    ec_mutex_unlock(&master->master_mutex);/** \fixme sc or domain could be
+                                             invalidated */
 
     ret = ecrt_slave_config_reg_pdo_entry(sc, data.entry_index,
             data.entry_subindex, domain, &data.bit_position);
@@ -2335,7 +2346,8 @@
         return -ENOENT;
     }
 
-    ec_mutex_unlock(&master->master_mutex); // FIXME
+    ec_mutex_unlock(&master->master_mutex); /** \fixme sc could be invalidated
+                                             */
 
     if (data.complete_access) {
         ret = ecrt_slave_config_complete_sdo(sc,
@@ -2466,18 +2478,15 @@
         return -EFAULT;
     }
 
-    if (ec_mutex_lock_interruptible(&master->master_mutex))
-        return -EINTR;
+    /* no locking of master_mutex needed, because sc will not be deleted in
+     * the meantime. */
 
     if (!(sc = ec_master_get_config_const(master, data.config_index))) {
-        ec_mutex_unlock(&master->master_mutex);
         return -ENOENT;
     }
 
     ecrt_slave_config_state(sc, &state);
 
-    ec_mutex_unlock(&master->master_mutex);
-
     if (copy_to_user((void __user *) data.state, &state, sizeof(state)))
         return -EFAULT;
 
@@ -2528,7 +2537,8 @@
         return -ENOENT;
     }
 
-    ec_mutex_unlock(&master->master_mutex); // FIXME
+    ec_mutex_unlock(&master->master_mutex);/** \fixme sc could be invalidated
+                                             */
 
     ret = ecrt_slave_config_idn(
             sc, ioctl.drive_no, ioctl.idn, ioctl.al_state, data, ioctl.size);
@@ -2583,16 +2593,14 @@
     if (unlikely(!priv->requested))
         return -EPERM;
 
-    if (ec_mutex_lock_interruptible(&master->master_mutex))
-        return -EINTR;
+    /* no locking of master_mutex needed, because domain will not be deleted
+     * in the meantime. */
 
     if (!(domain = ec_master_find_domain(master, arg))) {
-        ec_mutex_unlock(&master->master_mutex);
         return -ENOENT;
     }
 
     ecrt_domain_process(domain);
-    ec_mutex_unlock(&master->master_mutex);
     return 0;
 }
 
@@ -2611,16 +2619,14 @@
     if (unlikely(!priv->requested))
         return -EPERM;
 
-    if (ec_mutex_lock_interruptible(&master->master_mutex))
-        return -EINTR;
+    /* no locking of master_mutex needed, because domain will not be deleted
+     * in the meantime. */
 
     if (!(domain = ec_master_find_domain(master, arg))) {
-        ec_mutex_unlock(&master->master_mutex);
         return -ENOENT;
     }
 
     ecrt_domain_queue(domain);
-    ec_mutex_unlock(&master->master_mutex);
     return 0;
 }
 
@@ -2645,18 +2651,15 @@
         return -EFAULT;
     }
 
-    if (ec_mutex_lock_interruptible(&master->master_mutex))
-        return -EINTR;
+    /* no locking of master_mutex needed, because domain will not be deleted
+     * in the meantime. */
 
     if (!(domain = ec_master_find_domain_const(master, data.domain_index))) {
-        ec_mutex_unlock(&master->master_mutex);
         return -ENOENT;
     }
 
     ecrt_domain_state(domain, &state);
 
-    ec_mutex_unlock(&master->master_mutex);
-
     if (copy_to_user((void __user *) data.state, &state, sizeof(state)))
         return -EFAULT;
 
@@ -2683,21 +2686,17 @@
     if (copy_from_user(&data, (void __user *) arg, sizeof(data)))
         return -EFAULT;
 
-    if (ec_mutex_lock_interruptible(&master->master_mutex))
-        return -EINTR;
+    /* no locking of master_mutex needed, because neither sc nor req will not
+     * be deleted in the meantime. */
 
     if (!(sc = ec_master_get_config(master, data.config_index))) {
-        ec_mutex_unlock(&master->master_mutex);
         return -ENOENT;
     }
 
     if (!(req = ec_slave_config_find_sdo_request(sc, data.request_index))) {
-        ec_mutex_unlock(&master->master_mutex);
         return -ENOENT;
     }
 
-    ec_mutex_unlock(&master->master_mutex);
-
     ecrt_sdo_request_timeout(req, data.timeout);
     return 0;
 }
@@ -2722,16 +2721,14 @@
     if (copy_from_user(&data, (void __user *) arg, sizeof(data)))
         return -EFAULT;
 
-    if (ec_mutex_lock_interruptible(&master->master_mutex))
-        return -EINTR;
+    /* no locking of master_mutex needed, because neither sc nor req will not
+     * be deleted in the meantime. */
 
     if (!(sc = ec_master_get_config(master, data.config_index))) {
-        ec_mutex_unlock(&master->master_mutex);
         return -ENOENT;
     }
 
     if (!(req = ec_slave_config_find_sdo_request(sc, data.request_index))) {
-        ec_mutex_unlock(&master->master_mutex);
         return -ENOENT;
     }
 
@@ -2741,8 +2738,6 @@
     else
         data.size = 0;
 
-    ec_mutex_unlock(&master->master_mutex);
-
     if (copy_to_user((void __user *) arg, &data, sizeof(data)))
         return -EFAULT;
 
@@ -2769,21 +2764,17 @@
     if (copy_from_user(&data, (void __user *) arg, sizeof(data)))
         return -EFAULT;
 
-    if (ec_mutex_lock_interruptible(&master->master_mutex))
-        return -EINTR;
+    /* no locking of master_mutex needed, because neither sc nor req will not
+     * be deleted in the meantime. */
 
     if (!(sc = ec_master_get_config(master, data.config_index))) {
-        ec_mutex_unlock(&master->master_mutex);
         return -ENOENT;
     }
 
     if (!(req = ec_slave_config_find_sdo_request(sc, data.request_index))) {
-        ec_mutex_unlock(&master->master_mutex);
         return -ENOENT;
     }
 
-    ec_mutex_unlock(&master->master_mutex);
-
     ecrt_sdo_request_read(req);
     return 0;
 }
@@ -2814,21 +2805,17 @@
         return -EINVAL;
     }
 
-    if (ec_mutex_lock_interruptible(&master->master_mutex))
-        return -EINTR;
+    /* no locking of master_mutex needed, because neither sc nor req will not
+     * be deleted in the meantime. */
 
     if (!(sc = ec_master_get_config(master, data.config_index))) {
-        ec_mutex_unlock(&master->master_mutex);
         return -ENOENT;
     }
 
     if (!(req = ec_slave_config_find_sdo_request(sc, data.request_index))) {
-        ec_mutex_unlock(&master->master_mutex);
         return -ENOENT;
     }
 
-    ec_mutex_unlock(&master->master_mutex);
-
     ret = ec_sdo_request_alloc(req, data.size);
     if (ret)
         return ret;
@@ -2861,21 +2848,17 @@
     if (copy_from_user(&data, (void __user *) arg, sizeof(data)))
         return -EFAULT;
 
-    if (ec_mutex_lock_interruptible(&master->master_mutex))
-        return -EINTR;
+    /* no locking of master_mutex needed, because neither sc nor req will not
+     * be deleted in the meantime. */
 
     if (!(sc = ec_master_get_config(master, data.config_index))) {
-        ec_mutex_unlock(&master->master_mutex);
         return -ENOENT;
     }
 
     if (!(req = ec_slave_config_find_sdo_request(sc, data.request_index))) {
-        ec_mutex_unlock(&master->master_mutex);
         return -ENOENT;
     }
 
-    ec_mutex_unlock(&master->master_mutex);
-
     if (copy_to_user((void __user *) data.data, ecrt_sdo_request_data(req),
                 ecrt_sdo_request_data_size(req)))
         return -EFAULT;
@@ -2911,21 +2894,17 @@
     if (get_user(vendor_type, data.vendor_type))
         return -EFAULT;
 
-    if (ec_mutex_lock_interruptible(&master->master_mutex))
-        return -EINTR;
+    /* no locking of master_mutex needed, because neither sc nor voe will not
+     * be deleted in the meantime. */
 
     if (!(sc = ec_master_get_config(master, data.config_index))) {
-        ec_mutex_unlock(&master->master_mutex);
         return -ENOENT;
     }
 
     if (!(voe = ec_slave_config_find_voe_handler(sc, data.voe_index))) {
-        ec_mutex_unlock(&master->master_mutex);
         return -ENOENT;
     }
 
-    ec_mutex_unlock(&master->master_mutex);
-
     ecrt_voe_handler_send_header(voe, vendor_id, vendor_type);
     return 0;
 }
@@ -2952,23 +2931,19 @@
     if (copy_from_user(&data, (void __user *) arg, sizeof(data)))
         return -EFAULT;
 
-    if (ec_mutex_lock_interruptible(&master->master_mutex))
-        return -EINTR;
+    /* no locking of master_mutex needed, because neither sc nor voe will not
+     * be deleted in the meantime. */
 
     if (!(sc = ec_master_get_config(master, data.config_index))) {
-        ec_mutex_unlock(&master->master_mutex);
         return -ENOENT;
     }
 
     if (!(voe = ec_slave_config_find_voe_handler(sc, data.voe_index))) {
-        ec_mutex_unlock(&master->master_mutex);
         return -ENOENT;
     }
 
     ecrt_voe_handler_received_header(voe, &vendor_id, &vendor_type);
 
-    ec_mutex_unlock(&master->master_mutex);
-
     if (likely(data.vendor_id))
         if (put_user(vendor_id, data.vendor_id))
             return -EFAULT;
@@ -3000,21 +2975,17 @@
     if (copy_from_user(&data, (void __user *) arg, sizeof(data)))
         return -EFAULT;
 
-    if (ec_mutex_lock_interruptible(&master->master_mutex))
-        return -EINTR;
+    /* no locking of master_mutex needed, because neither sc nor voe will not
+     * be deleted in the meantime. */
 
     if (!(sc = ec_master_get_config(master, data.config_index))) {
-        ec_mutex_unlock(&master->master_mutex);
         return -ENOENT;
     }
 
     if (!(voe = ec_slave_config_find_voe_handler(sc, data.voe_index))) {
-        ec_mutex_unlock(&master->master_mutex);
         return -ENOENT;
     }
 
-    ec_mutex_unlock(&master->master_mutex);
-
     ecrt_voe_handler_read(voe);
     return 0;
 }
@@ -3039,21 +3010,17 @@
     if (copy_from_user(&data, (void __user *) arg, sizeof(data)))
         return -EFAULT;
 
-    if (ec_mutex_lock_interruptible(&master->master_mutex))
-        return -EINTR;
+    /* no locking of master_mutex needed, because neither sc nor voe will not
+     * be deleted in the meantime. */
 
     if (!(sc = ec_master_get_config(master, data.config_index))) {
-        ec_mutex_unlock(&master->master_mutex);
         return -ENOENT;
     }
 
     if (!(voe = ec_slave_config_find_voe_handler(sc, data.voe_index))) {
-        ec_mutex_unlock(&master->master_mutex);
         return -ENOENT;
     }
 
-    ec_mutex_unlock(&master->master_mutex);
-
     ecrt_voe_handler_read_nosync(voe);
     return 0;
 }
@@ -3078,21 +3045,17 @@
     if (copy_from_user(&data, (void __user *) arg, sizeof(data)))
         return -EFAULT;
 
-    if (ec_mutex_lock_interruptible(&master->master_mutex))
-        return -EINTR;
+    /* no locking of master_mutex needed, because neither sc nor voe will not
+     * be deleted in the meantime. */
 
     if (!(sc = ec_master_get_config(master, data.config_index))) {
-        ec_mutex_unlock(&master->master_mutex);
         return -ENOENT;
     }
 
     if (!(voe = ec_slave_config_find_voe_handler(sc, data.voe_index))) {
-        ec_mutex_unlock(&master->master_mutex);
         return -ENOENT;
     }
 
-    ec_mutex_unlock(&master->master_mutex);
-
     if (data.size) {
         if (data.size > ec_voe_handler_mem_size(voe))
             return -EOVERFLOW;
@@ -3126,21 +3089,17 @@
     if (copy_from_user(&data, (void __user *) arg, sizeof(data)))
         return -EFAULT;
 
-    if (ec_mutex_lock_interruptible(&master->master_mutex))
-        return -EINTR;
+    /* no locking of master_mutex needed, because neither sc nor voe will not
+     * be deleted in the meantime. */
 
     if (!(sc = ec_master_get_config(master, data.config_index))) {
-        ec_mutex_unlock(&master->master_mutex);
         return -ENOENT;
     }
 
     if (!(voe = ec_slave_config_find_voe_handler(sc, data.voe_index))) {
-        ec_mutex_unlock(&master->master_mutex);
         return -ENOENT;
     }
 
-    ec_mutex_unlock(&master->master_mutex);
-
     data.state = ecrt_voe_handler_execute(voe);
     if (data.state == EC_REQUEST_SUCCESS && voe->dir == EC_DIR_INPUT)
         data.size = ecrt_voe_handler_data_size(voe);
@@ -3173,21 +3132,17 @@
     if (copy_from_user(&data, (void __user *) arg, sizeof(data)))
         return -EFAULT;
 
-    if (ec_mutex_lock_interruptible(&master->master_mutex))
-        return -EINTR;
+    /* no locking of master_mutex needed, because neither sc nor voe will not
+     * be deleted in the meantime. */
 
     if (!(sc = ec_master_get_config(master, data.config_index))) {
-        ec_mutex_unlock(&master->master_mutex);
         return -ENOENT;
     }
 
     if (!(voe = ec_slave_config_find_voe_handler(sc, data.voe_index))) {
-        ec_mutex_unlock(&master->master_mutex);
         return -ENOENT;
     }
 
-    ec_mutex_unlock(&master->master_mutex);
-
     if (copy_to_user((void __user *) data.data, ecrt_voe_handler_data(voe),
                 ecrt_voe_handler_data_size(voe)))
         return -EFAULT;
@@ -3326,8 +3281,10 @@
     request->req.data_size = data.buffer_size;
     ec_foe_request_write(&request->req);
 
-    if (ec_mutex_lock_interruptible(&master->master_mutex))
+    if (ec_mutex_lock_interruptible(&master->master_mutex)) {
+        kref_put(&request->refcount, ec_master_foe_request_release);
         return -EINTR;
+    }
 
     if (!(request->slave = ec_master_find_slave(
                     master, 0, data.slave_position))) {
@@ -3522,8 +3479,13 @@
  */
 long eccdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
+#if DEBUG_LATENCY
+    cycles_t a = get_cycles(), b;
+    unsigned int t;
+#endif
     ec_cdev_priv_t *priv = (ec_cdev_priv_t *) filp->private_data;
     ec_master_t *master = priv->cdev->master;
+    int ret;
 
 #if DEBUG_IOCTL
     EC_MASTER_DBG(master, 0, "ioctl(filp = 0x%p, cmd = 0x%08x (0x%02x),"
@@ -3532,252 +3494,430 @@
 
     switch (cmd) {
         case EC_IOCTL_MODULE:
-            return ec_cdev_ioctl_module(arg);
+            ret = ec_cdev_ioctl_module(arg);
+            break;
         case EC_IOCTL_MASTER:
-            return ec_cdev_ioctl_master(master, arg);
+            ret = ec_cdev_ioctl_master(master, arg);
+            break;
         case EC_IOCTL_SLAVE:
-            return ec_cdev_ioctl_slave(master, arg);
+            ret = ec_cdev_ioctl_slave(master, arg);
+            break;
         case EC_IOCTL_SLAVE_SYNC:
-            return ec_cdev_ioctl_slave_sync(master, arg);
+            ret = ec_cdev_ioctl_slave_sync(master, arg);
+            break;
         case EC_IOCTL_SLAVE_SYNC_PDO:
-            return ec_cdev_ioctl_slave_sync_pdo(master, arg);
+            ret = ec_cdev_ioctl_slave_sync_pdo(master, arg);
+            break;
         case EC_IOCTL_SLAVE_SYNC_PDO_ENTRY:
-            return ec_cdev_ioctl_slave_sync_pdo_entry(master, arg);
+            ret = ec_cdev_ioctl_slave_sync_pdo_entry(master, arg);
+            break;
         case EC_IOCTL_DOMAIN:
-            return ec_cdev_ioctl_domain(master, arg);
+            ret = ec_cdev_ioctl_domain(master, arg);
+            break;
         case EC_IOCTL_DOMAIN_FMMU:
-            return ec_cdev_ioctl_domain_fmmu(master, arg);
+            ret = ec_cdev_ioctl_domain_fmmu(master, arg);
+            break;
         case EC_IOCTL_DOMAIN_DATA:
-            return ec_cdev_ioctl_domain_data(master, arg);
+            ret = ec_cdev_ioctl_domain_data(master, arg);
+            break;
         case EC_IOCTL_MASTER_DEBUG:
-            if (!(filp->f_mode & FMODE_WRITE))
-                return -EPERM;
-            return ec_cdev_ioctl_master_debug(master, arg);
+            if (!(filp->f_mode & FMODE_WRITE)) {
+                ret = -EPERM;
+                break;
+            }
+            ret = ec_cdev_ioctl_master_debug(master, arg);
+            break;
         case EC_IOCTL_MASTER_RESCAN:
-            if (!(filp->f_mode & FMODE_WRITE))
-                return -EPERM;
-            return ec_cdev_ioctl_master_rescan(master, arg);
+            if (!(filp->f_mode & FMODE_WRITE)) {
+                ret = -EPERM;
+                break;
+            }
+            ret = ec_cdev_ioctl_master_rescan(master, arg);
+            break;
         case EC_IOCTL_SLAVE_STATE:
-            if (!(filp->f_mode & FMODE_WRITE))
-                return -EPERM;
-            return ec_cdev_ioctl_slave_state(master, arg);
+            if (!(filp->f_mode & FMODE_WRITE)) {
+                ret = -EPERM;
+                break;
+            }
+            ret = ec_cdev_ioctl_slave_state(master, arg);
+            break;
         case EC_IOCTL_SLAVE_SDO:
-            return ec_cdev_ioctl_slave_sdo(master, arg);
+            ret = ec_cdev_ioctl_slave_sdo(master, arg);
+            break;
         case EC_IOCTL_SLAVE_SDO_ENTRY:
-            return ec_cdev_ioctl_slave_sdo_entry(master, arg);
+            ret = ec_cdev_ioctl_slave_sdo_entry(master, arg);
+            break;
         case EC_IOCTL_SLAVE_SDO_UPLOAD:
-            return ec_cdev_ioctl_slave_sdo_upload(master, arg);
+            ret = ec_cdev_ioctl_slave_sdo_upload(master, arg);
+            break;
         case EC_IOCTL_SLAVE_SDO_DOWNLOAD:
-            if (!(filp->f_mode & FMODE_WRITE))
-                return -EPERM;
-            return ec_cdev_ioctl_slave_sdo_download(master, arg);
+            if (!(filp->f_mode & FMODE_WRITE)) {
+                ret = -EPERM;
+                break;
+            }
+            ret = ec_cdev_ioctl_slave_sdo_download(master, arg);
+            break;
         case EC_IOCTL_SLAVE_SII_READ:
-            return ec_cdev_ioctl_slave_sii_read(master, arg);
+            ret = ec_cdev_ioctl_slave_sii_read(master, arg);
+            break;
         case EC_IOCTL_SLAVE_SII_WRITE:
-            if (!(filp->f_mode & FMODE_WRITE))
-                return -EPERM;
-            return ec_cdev_ioctl_slave_sii_write(master, arg);
+            if (!(filp->f_mode & FMODE_WRITE)) {
+                ret = -EPERM;
+                break;
+            }
+            ret = ec_cdev_ioctl_slave_sii_write(master, arg);
+            break;
         case EC_IOCTL_SLAVE_REG_READ:
-            return ec_cdev_ioctl_slave_reg_read(master, arg);
+            ret = ec_cdev_ioctl_slave_reg_read(master, arg);
+            break;
         case EC_IOCTL_SLAVE_REG_WRITE:
-            if (!(filp->f_mode & FMODE_WRITE))
-                return -EPERM;
-            return ec_cdev_ioctl_slave_reg_write(master, arg);
+            if (!(filp->f_mode & FMODE_WRITE)) {
+                ret = -EPERM;
+                break;
+            }
+            ret = ec_cdev_ioctl_slave_reg_write(master, arg);
+            break;
         case EC_IOCTL_SLAVE_FOE_READ:
-            return ec_cdev_ioctl_slave_foe_read(master, arg);
+            ret = ec_cdev_ioctl_slave_foe_read(master, arg);
+            break;
         case EC_IOCTL_SLAVE_FOE_WRITE:
-            if (!(filp->f_mode & FMODE_WRITE))
-                return -EPERM;
-            return ec_cdev_ioctl_slave_foe_write(master, arg);
+            if (!(filp->f_mode & FMODE_WRITE)) {
+                ret = -EPERM;
+                break;
+            }
+            ret = ec_cdev_ioctl_slave_foe_write(master, arg);
+            break;
         case EC_IOCTL_SLAVE_SOE_READ:
-            return ec_cdev_ioctl_slave_soe_read(master, arg);
+            ret = ec_cdev_ioctl_slave_soe_read(master, arg);
+            break;
         case EC_IOCTL_SLAVE_SOE_WRITE:
-            if (!(filp->f_mode & FMODE_WRITE))
-                return -EPERM;
-            return ec_cdev_ioctl_slave_soe_write(master, arg);
+            if (!(filp->f_mode & FMODE_WRITE)) {
+                ret = -EPERM;
+                break;
+            }
+            ret = ec_cdev_ioctl_slave_soe_write(master, arg);
+            break;
         case EC_IOCTL_CONFIG:
-            return ec_cdev_ioctl_config(master, arg);
+            ret = ec_cdev_ioctl_config(master, arg);
+            break;
         case EC_IOCTL_CONFIG_PDO:
-            return ec_cdev_ioctl_config_pdo(master, arg);
+            ret = ec_cdev_ioctl_config_pdo(master, arg);
+            break;
         case EC_IOCTL_CONFIG_PDO_ENTRY:
-            return ec_cdev_ioctl_config_pdo_entry(master, arg);
+            ret = ec_cdev_ioctl_config_pdo_entry(master, arg);
+            break;
         case EC_IOCTL_CONFIG_SDO:
-            return ec_cdev_ioctl_config_sdo(master, arg);
+            ret = ec_cdev_ioctl_config_sdo(master, arg);
+            break;
         case EC_IOCTL_CONFIG_IDN:
-            return ec_cdev_ioctl_config_idn(master, arg);
+            ret = ec_cdev_ioctl_config_idn(master, arg);
+            break;
 #ifdef EC_EOE
         case EC_IOCTL_EOE_HANDLER:
-            return ec_cdev_ioctl_eoe_handler(master, arg);
+            ret = ec_cdev_ioctl_eoe_handler(master, arg);
+            break;
 #endif
         case EC_IOCTL_REQUEST:
-            if (!(filp->f_mode & FMODE_WRITE))
-                return -EPERM;
-            return ec_cdev_ioctl_request(master, arg, priv);
+            if (!(filp->f_mode & FMODE_WRITE)) {
+                ret = -EPERM;
+                break;
+            }
+            ret = ec_cdev_ioctl_request(master, arg, priv);
+            break;
         case EC_IOCTL_CREATE_DOMAIN:
-            if (!(filp->f_mode & FMODE_WRITE))
-                return -EPERM;
-            return ec_cdev_ioctl_create_domain(master, arg, priv);
+            if (!(filp->f_mode & FMODE_WRITE)) {
+                ret = -EPERM;
+                break;
+            }
+            ret = ec_cdev_ioctl_create_domain(master, arg, priv);
+            break;
         case EC_IOCTL_CREATE_SLAVE_CONFIG:
-            if (!(filp->f_mode & FMODE_WRITE))
-                return -EPERM;
-            return ec_cdev_ioctl_create_slave_config(master, arg, priv);
+            if (!(filp->f_mode & FMODE_WRITE)) {
+                ret = -EPERM;
+                break;
+            }
+            ret = ec_cdev_ioctl_create_slave_config(master, arg, priv);
+            break;
         case EC_IOCTL_ACTIVATE:
-            if (!(filp->f_mode & FMODE_WRITE))
-                return -EPERM;
-            return ec_cdev_ioctl_activate(master, arg, priv);
+            if (!(filp->f_mode & FMODE_WRITE)) {
+                ret = -EPERM;
+                break;
+            }
+            ret = ec_cdev_ioctl_activate(master, arg, priv);
+            break;
         case EC_IOCTL_DEACTIVATE:
-            if (!(filp->f_mode & FMODE_WRITE))
-                return -EPERM;
-            return ec_cdev_ioctl_deactivate(master, arg, priv);
+            if (!(filp->f_mode & FMODE_WRITE)) {
+                ret = -EPERM;
+                break;
+            }
+            ret = ec_cdev_ioctl_deactivate(master, arg, priv);
+            break;
         case EC_IOCTL_SEND:
-            if (!(filp->f_mode & FMODE_WRITE))
-                return -EPERM;
-            return ec_cdev_ioctl_send(master, arg, priv);
+            if (!(filp->f_mode & FMODE_WRITE)) {
+                ret = -EPERM;
+                break;
+            }
+            ret = ec_cdev_ioctl_send(master, arg, priv);
+            break;
         case EC_IOCTL_RECEIVE:
-            if (!(filp->f_mode & FMODE_WRITE))
-                return -EPERM;
-            return ec_cdev_ioctl_receive(master, arg, priv);
+            if (!(filp->f_mode & FMODE_WRITE)) {
+                ret = -EPERM;
+                break;
+            }
+            ret = ec_cdev_ioctl_receive(master, arg, priv);
+            break;
         case EC_IOCTL_MASTER_STATE:
-            return ec_cdev_ioctl_master_state(master, arg, priv);
+            ret = ec_cdev_ioctl_master_state(master, arg, priv);
+            break;
         case EC_IOCTL_MASTER_SC_STATE:
-            return ec_cdev_ioctl_master_sc_state(master, arg, priv);
+            ret = ec_cdev_ioctl_master_sc_state(master, arg, priv);
+            break;
         case EC_IOCTL_APP_TIME:
-            if (!(filp->f_mode & FMODE_WRITE))
-                return -EPERM;
-            return ec_cdev_ioctl_app_time(master, arg, priv);
+            if (!(filp->f_mode & FMODE_WRITE)) {
+                ret = -EPERM;
+                break;
+            }
+            ret = ec_cdev_ioctl_app_time(master, arg, priv);
+            break;
         case EC_IOCTL_SYNC_REF:
-            if (!(filp->f_mode & FMODE_WRITE))
-                return -EPERM;
-            return ec_cdev_ioctl_sync_ref(master, arg, priv);
+            if (!(filp->f_mode & FMODE_WRITE)) {
+                ret = -EPERM;
+                break;
+            }
+            ret = ec_cdev_ioctl_sync_ref(master, arg, priv);
+            break;
         case EC_IOCTL_SYNC_SLAVES:
-            if (!(filp->f_mode & FMODE_WRITE))
-                return -EPERM;
-            return ec_cdev_ioctl_sync_slaves(master, arg, priv);
+            if (!(filp->f_mode & FMODE_WRITE)) {
+                ret = -EPERM;
+                break;
+            }
+            ret = ec_cdev_ioctl_sync_slaves(master, arg, priv);
+            break;
         case EC_IOCTL_SYNC_MON_QUEUE:
-            if (!(filp->f_mode & FMODE_WRITE))
-                return -EPERM;
-            return ec_cdev_ioctl_sync_mon_queue(master, arg, priv);
+            if (!(filp->f_mode & FMODE_WRITE)) {
+                ret = -EPERM;
+                break;
+            }
+            ret = ec_cdev_ioctl_sync_mon_queue(master, arg, priv);
+            break;
         case EC_IOCTL_SYNC_MON_PROCESS:
-            if (!(filp->f_mode & FMODE_WRITE))
-                return -EPERM;
-            return ec_cdev_ioctl_sync_mon_process(master, arg, priv);
+            if (!(filp->f_mode & FMODE_WRITE)) {
+                ret = -EPERM;
+                break;
+            }
+            ret = ec_cdev_ioctl_sync_mon_process(master, arg, priv);
+            break;
         case EC_IOCTL_RESET:
-            if (!(filp->f_mode & FMODE_WRITE))
-                return -EPERM;
-            return ec_cdev_ioctl_reset(master, arg, priv);
+            if (!(filp->f_mode & FMODE_WRITE)) {
+                ret = -EPERM;
+                break;
+            }
+            ret = ec_cdev_ioctl_reset(master, arg, priv);
+            break;
         case EC_IOCTL_SC_SYNC:
-            if (!(filp->f_mode & FMODE_WRITE))
-                return -EPERM;
-            return ec_cdev_ioctl_sc_sync(master, arg, priv);
+            if (!(filp->f_mode & FMODE_WRITE)) {
+                ret = -EPERM;
+                break;
+            }
+            ret = ec_cdev_ioctl_sc_sync(master, arg, priv);
+            break;
         case EC_IOCTL_SC_WATCHDOG:
-            if (!(filp->f_mode & FMODE_WRITE))
-                return -EPERM;
-            return ec_cdev_ioctl_sc_watchdog(master, arg, priv);
+            if (!(filp->f_mode & FMODE_WRITE)) {
+                ret = -EPERM;
+                break;
+            }
+            ret = ec_cdev_ioctl_sc_watchdog(master, arg, priv);
+            break;
         case EC_IOCTL_SC_OVERLAPPING_IO:
-            if (!(filp->f_mode & FMODE_WRITE))
-                return -EPERM;
-            return ec_cdev_ioctl_sc_allow_overlapping_pdos(master, arg, priv);
+            if (!(filp->f_mode & FMODE_WRITE)) {
+                ret = -EPERM;
+                break;
+            }
+            ret = ec_cdev_ioctl_sc_allow_overlapping_pdos(master, arg, priv);
+            break;
         case EC_IOCTL_SC_ADD_PDO:
-            if (!(filp->f_mode & FMODE_WRITE))
-                return -EPERM;
-            return ec_cdev_ioctl_sc_add_pdo(master, arg, priv);
+            if (!(filp->f_mode & FMODE_WRITE)) {
+                ret = -EPERM;
+                break;
+            }
+            ret = ec_cdev_ioctl_sc_add_pdo(master, arg, priv);
+            break;
         case EC_IOCTL_SC_CLEAR_PDOS:
-            if (!(filp->f_mode & FMODE_WRITE))
-                return -EPERM;
-            return ec_cdev_ioctl_sc_clear_pdos(master, arg, priv);
+            if (!(filp->f_mode & FMODE_WRITE)) {
+                ret = -EPERM;
+                break;
+            }
+            ret = ec_cdev_ioctl_sc_clear_pdos(master, arg, priv);
+            break;
         case EC_IOCTL_SC_ADD_ENTRY:
-            if (!(filp->f_mode & FMODE_WRITE))
-                return -EPERM;
-            return ec_cdev_ioctl_sc_add_entry(master, arg, priv);
+            if (!(filp->f_mode & FMODE_WRITE)) {
+                ret = -EPERM;
+                break;
+            }
+            ret = ec_cdev_ioctl_sc_add_entry(master, arg, priv);
+            break;
         case EC_IOCTL_SC_CLEAR_ENTRIES:
-            if (!(filp->f_mode & FMODE_WRITE))
-                return -EPERM;
-            return ec_cdev_ioctl_sc_clear_entries(master, arg, priv);
+            if (!(filp->f_mode & FMODE_WRITE)) {
+                ret = -EPERM;
+                break;
+            }
+            ret = ec_cdev_ioctl_sc_clear_entries(master, arg, priv);
+            break;
         case EC_IOCTL_SC_REG_PDO_ENTRY:
-            if (!(filp->f_mode & FMODE_WRITE))
-                return -EPERM;
-            return ec_cdev_ioctl_sc_reg_pdo_entry(master, arg, priv);
+            if (!(filp->f_mode & FMODE_WRITE)) {
+                ret = -EPERM;
+                break;
+            }
+            ret = ec_cdev_ioctl_sc_reg_pdo_entry(master, arg, priv);
+            break;
         case EC_IOCTL_SC_DC:
-            if (!(filp->f_mode & FMODE_WRITE))
-                return -EPERM;
-            return ec_cdev_ioctl_sc_dc(master, arg, priv);
+            if (!(filp->f_mode & FMODE_WRITE)) {
+                ret = -EPERM;
+                break;
+            }
+            ret = ec_cdev_ioctl_sc_dc(master, arg, priv);
+            break;
         case EC_IOCTL_SC_SDO:
-            if (!(filp->f_mode & FMODE_WRITE))
-                return -EPERM;
-            return ec_cdev_ioctl_sc_sdo(master, arg, priv);
+            if (!(filp->f_mode & FMODE_WRITE)) {
+                ret = -EPERM;
+                break;
+            }
+            ret = ec_cdev_ioctl_sc_sdo(master, arg, priv);
+            break;
         case EC_IOCTL_SC_SDO_REQUEST:
-            if (!(filp->f_mode & FMODE_WRITE))
-                return -EPERM;
-            return ec_cdev_ioctl_sc_create_sdo_request(master, arg, priv);
+            if (!(filp->f_mode & FMODE_WRITE)) {
+                ret = -EPERM;
+                break;
+            }
+            ret = ec_cdev_ioctl_sc_create_sdo_request(master, arg, priv);
+            break;
         case EC_IOCTL_SC_VOE:
-            if (!(filp->f_mode & FMODE_WRITE))
-                return -EPERM;
-            return ec_cdev_ioctl_sc_create_voe_handler(master, arg, priv);
+            if (!(filp->f_mode & FMODE_WRITE)) {
+                ret = -EPERM;
+                break;
+            }
+            ret = ec_cdev_ioctl_sc_create_voe_handler(master, arg, priv);
+            break;
         case EC_IOCTL_SC_STATE:
-            return ec_cdev_ioctl_sc_state(master, arg, priv);
+            ret = ec_cdev_ioctl_sc_state(master, arg, priv);
+            break;
         case EC_IOCTL_SC_IDN:
-            if (!(filp->f_mode & FMODE_WRITE))
-                return -EPERM;
-            return ec_cdev_ioctl_sc_idn(master, arg, priv);
+            if (!(filp->f_mode & FMODE_WRITE)) {
+                ret = -EPERM;
+                break;
+            }
+            ret = ec_cdev_ioctl_sc_idn(master, arg, priv);
+            break;
         case EC_IOCTL_DOMAIN_OFFSET:
-            return ec_cdev_ioctl_domain_offset(master, arg, priv);
+            ret = ec_cdev_ioctl_domain_offset(master, arg, priv);
+            break;
         case EC_IOCTL_DOMAIN_PROCESS:
-            if (!(filp->f_mode & FMODE_WRITE))
-                return -EPERM;
-            return ec_cdev_ioctl_domain_process(master, arg, priv);
+            if (!(filp->f_mode & FMODE_WRITE)) {
+                ret = -EPERM;
+                break;
+            }
+            ret = ec_cdev_ioctl_domain_process(master, arg, priv);
+            break;
         case EC_IOCTL_DOMAIN_QUEUE:
-            if (!(filp->f_mode & FMODE_WRITE))
-                return -EPERM;
-            return ec_cdev_ioctl_domain_queue(master, arg, priv);
+            if (!(filp->f_mode & FMODE_WRITE)) {
+                ret = -EPERM;
+                break;
+            }
+            ret = ec_cdev_ioctl_domain_queue(master, arg, priv);
+            break;
         case EC_IOCTL_DOMAIN_STATE:
-            return ec_cdev_ioctl_domain_state(master, arg, priv);
+            ret = ec_cdev_ioctl_domain_state(master, arg, priv);
+            break;
         case EC_IOCTL_SDO_REQUEST_TIMEOUT:
-            if (!(filp->f_mode & FMODE_WRITE))
-                return -EPERM;
-            return ec_cdev_ioctl_sdo_request_timeout(master, arg, priv);
+            if (!(filp->f_mode & FMODE_WRITE)) {
+                ret = -EPERM;
+                break;
+            }
+            ret = ec_cdev_ioctl_sdo_request_timeout(master, arg, priv);
+            break;
         case EC_IOCTL_SDO_REQUEST_STATE:
-            return ec_cdev_ioctl_sdo_request_state(master, arg, priv);
+            ret = ec_cdev_ioctl_sdo_request_state(master, arg, priv);
+            break;
         case EC_IOCTL_SDO_REQUEST_READ:
-            if (!(filp->f_mode & FMODE_WRITE))
-                return -EPERM;
-            return ec_cdev_ioctl_sdo_request_read(master, arg, priv);
+            if (!(filp->f_mode & FMODE_WRITE)) {
+                ret = -EPERM;
+                break;
+            }
+            ret = ec_cdev_ioctl_sdo_request_read(master, arg, priv);
+            break;
         case EC_IOCTL_SDO_REQUEST_WRITE:
-            if (!(filp->f_mode & FMODE_WRITE))
-                return -EPERM;
-            return ec_cdev_ioctl_sdo_request_write(master, arg, priv);
+            if (!(filp->f_mode & FMODE_WRITE)) {
+                ret = -EPERM;
+                break;
+            }
+            ret = ec_cdev_ioctl_sdo_request_write(master, arg, priv);
+            break;
         case EC_IOCTL_SDO_REQUEST_DATA:
-            return ec_cdev_ioctl_sdo_request_data(master, arg, priv);
+            ret = ec_cdev_ioctl_sdo_request_data(master, arg, priv);
+            break;
         case EC_IOCTL_VOE_SEND_HEADER:
-            if (!(filp->f_mode & FMODE_WRITE))
-                return -EPERM;
-            return ec_cdev_ioctl_voe_send_header(master, arg, priv);
+            if (!(filp->f_mode & FMODE_WRITE)) {
+                ret = -EPERM;
+                break;
+            }
+            ret = ec_cdev_ioctl_voe_send_header(master, arg, priv);
+            break;
         case EC_IOCTL_VOE_REC_HEADER:
-            return ec_cdev_ioctl_voe_rec_header(master, arg, priv);
+            ret = ec_cdev_ioctl_voe_rec_header(master, arg, priv);
+            break;
         case EC_IOCTL_VOE_READ:
-            if (!(filp->f_mode & FMODE_WRITE))
-                return -EPERM;
-            return ec_cdev_ioctl_voe_read(master, arg, priv);
+            if (!(filp->f_mode & FMODE_WRITE)) {
+                ret = -EPERM;
+                break;
+            }
+            ret = ec_cdev_ioctl_voe_read(master, arg, priv);
+            break;
         case EC_IOCTL_VOE_READ_NOSYNC:
-            if (!(filp->f_mode & FMODE_WRITE))
-                return -EPERM;
-            return ec_cdev_ioctl_voe_read_nosync(master, arg, priv);
+            if (!(filp->f_mode & FMODE_WRITE)) {
+                ret = -EPERM;
+                break;
+            }
+            ret = ec_cdev_ioctl_voe_read_nosync(master, arg, priv);
+            break;
         case EC_IOCTL_VOE_WRITE:
-            if (!(filp->f_mode & FMODE_WRITE))
-                return -EPERM;
-            return ec_cdev_ioctl_voe_write(master, arg, priv);
+            if (!(filp->f_mode & FMODE_WRITE)) {
+                ret = -EPERM;
+                break;
+            }
+            ret = ec_cdev_ioctl_voe_write(master, arg, priv);
+            break;
         case EC_IOCTL_VOE_EXEC:
-            if (!(filp->f_mode & FMODE_WRITE))
-                return -EPERM;
-            return ec_cdev_ioctl_voe_exec(master, arg, priv);
+            if (!(filp->f_mode & FMODE_WRITE)) {
+                ret = -EPERM;
+                break;
+            }
+            ret = ec_cdev_ioctl_voe_exec(master, arg, priv);
+            break;
         case EC_IOCTL_VOE_DATA:
-            return ec_cdev_ioctl_voe_data(master, arg, priv);
+            ret = ec_cdev_ioctl_voe_data(master, arg, priv);
+            break;
         case EC_IOCTL_SET_SEND_INTERVAL:
-            if (!(filp->f_mode & FMODE_WRITE))
-                return -EPERM;
-            return ec_cdev_ioctl_set_send_interval(master, arg, priv);
+            if (!(filp->f_mode & FMODE_WRITE)) {
+                ret = -EPERM;
+                break;
+            }
+            ret = ec_cdev_ioctl_set_send_interval(master, arg, priv);
+            break;
         default:
-            return -ENOTTY;
-    }
+            ret = -ENOTTY;
+            break;
+    }
+
+#if DEBUG_LATENCY
+    b = get_cycles();
+    t = (unsigned int) ((b - a) * 1000LL) / cpu_khz;
+    if (t > 50) {
+        EC_MASTER_WARN(master, "ioctl(0x%02x) took %u us.\n",
+                _IOC_NR(cmd), t);
+    }
+#endif
+
+    return ret;
 }
 
 /*****************************************************************************/