Implemented master semaphore to secure concurrent access from ioctls, state machine and realtime interface.
authorFlorian Pose <fp@igh-essen.com>
Tue, 01 Jul 2008 15:38:20 +0000
changeset 1075 94c6e36e0f8d
parent 1074 a82793a6d1a0
child 1076 e62b492aab51
Implemented master semaphore to secure concurrent access from ioctls, state machine and realtime interface.
master/cdev.c
master/domain.c
master/master.c
master/master.h
master/slave_config.c
--- a/master/cdev.c	Mon Jun 30 15:51:46 2008 +0000
+++ b/master/cdev.c	Tue Jul 01 15:38:20 2008 +0000
@@ -138,8 +138,8 @@
         EC_DBG("ioctl(filp = %x, cmd = %u (%u), arg = %x)\n",
                 (u32) filp, (u32) cmd, (u32) _IOC_NR(cmd), (u32) arg);
 
-    // FIXME lock
-    
+    down(&master->master_sem);
+
     switch (cmd) {
         case EC_IOCTL_MASTER:
             {
@@ -1012,6 +1012,7 @@
             retval = -ENOTTY;
     }
 
+    up(&master->master_sem);
     return retval;
 }
 
--- a/master/domain.c	Mon Jun 30 15:51:46 2008 +0000
+++ b/master/domain.c	Tue Jul 01 15:38:20 2008 +0000
@@ -344,10 +344,14 @@
 
 void ecrt_domain_external_memory(ec_domain_t *domain, uint8_t *mem)
 {
+    down(&domain->master->master_sem);
+
     ec_domain_clear_data(domain);
 
     domain->data = mem;
     domain->data_origin = EC_ORIG_EXTERNAL;
+
+    up(&domain->master->master_sem);
 }
 
 /*****************************************************************************/
--- a/master/master.c	Mon Jun 30 15:51:46 2008 +0000
+++ b/master/master.c	Tue Jul 01 15:38:20 2008 +0000
@@ -85,6 +85,8 @@
     master->index = index;
     master->reserved = 0;
 
+    init_MUTEX(&master->master_sem);
+
     master->main_mac = main_mac;
     master->backup_mac = backup_mac;
     init_MUTEX(&master->device_sem);
@@ -360,13 +362,13 @@
         ec_master_t *master /**< EtherCAT master */
         )
 {
+    if (master->debug_level)
+        EC_DBG("ORPHANED -> IDLE.\n");
+
     master->request_cb = ec_master_request_cb;
     master->release_cb = ec_master_release_cb;
     master->cb_data = master;
 
-    if (master->debug_level)
-        EC_DBG("ORPHANED -> IDLE.\n");
-
     master->phase = EC_IDLE;
     if (ec_master_thread_start(master, ec_master_idle_thread)) {
         master->phase = EC_ORPHANED;
@@ -391,7 +393,10 @@
     ec_master_eoe_stop(master);
 #endif
     ec_master_thread_stop(master);
+
+    down(&master->master_sem);
     ec_master_clear_slaves(master);
+    up(&master->master_sem);
 }
 
 /*****************************************************************************/
@@ -457,9 +462,6 @@
     }
 #endif
 
-    if (master->debug_level)
-        EC_DBG("Switching to operation phase.\n");
-
     master->phase = EC_OPERATION;
     master->ext_request_cb = NULL;
     master->ext_release_cb = NULL;
@@ -498,8 +500,10 @@
     master->release_cb = ec_master_release_cb;
     master->cb_data = master;
     
+    down(&master->master_sem);
     ec_master_clear_domains(master);
     ec_master_clear_slave_configs(master);
+    up(&master->master_sem);
 
     // set states for all slaves
     for (slave = master->slaves;
@@ -826,7 +830,9 @@
             goto schedule;
 
         // execute master state machine
+        down(&master->master_sem);
         ec_fsm_master_exec(&master->fsm);
+        up(&master->master_sem);
 
         // queue and send
         spin_lock_bh(&master->internal_lock);
@@ -870,7 +876,9 @@
         ec_master_output_stats(master);
 
         // execute master state machine
+        down(&master->master_sem);
         ec_fsm_master_exec(&master->fsm);
+        up(&master->master_sem);
 
         // inject datagram
         master->injection_seq_fsm++;
@@ -1146,6 +1154,8 @@
         return NULL;
     }
 
+    down(&master->master_sem);
+
     if (list_empty(&master->domains)) {
         index = 0;
     } else {
@@ -1156,6 +1166,8 @@
     ec_domain_init(domain, master, index);
     list_add_tail(&domain->list, &master->domains);
 
+    up(&master->master_sem);
+
     return domain;
 }
 
@@ -1166,6 +1178,8 @@
     uint32_t domain_offset;
     ec_domain_t *domain;
 
+    down(&master->master_sem);
+
     // finish all domains
     domain_offset = 0;
     list_for_each_entry(domain, &master->domains, list) {
@@ -1175,6 +1189,8 @@
         }
         domain_offset += domain->data_size;
     }
+    
+    up(&master->master_sem);
 
     // restart EoE process and master thread with new locking
 #ifdef EC_EOE
@@ -1327,11 +1343,15 @@
         ec_slave_config_init(sc, master,
                 alias, position, vendor_id, product_code);
 
+
+        down(&master->master_sem);
+
         // try to find the addressed slave
         ec_slave_config_attach(sc);
         ec_slave_config_load_default_sync_config(sc);
-
         list_add_tail(&sc->list, &master->configs);
+
+        up(&master->master_sem);
     }
 
     return sc;
--- a/master/master.h	Mon Jun 30 15:51:46 2008 +0000
+++ b/master/master.h	Tue Jul 01 15:38:20 2008 +0000
@@ -88,6 +88,7 @@
 
     ec_cdev_t cdev; /**< Master character device. */
     struct class_device *class_device; /**< Master class device. */
+    struct semaphore master_sem; /**< Master semaphore. */
 
     ec_device_t main_device; /**< EtherCAT main device. */
     const uint8_t *main_mac; /**< MAC address of main device. */
--- a/master/slave_config.c	Mon Jun 30 15:51:46 2008 +0000
+++ b/master/slave_config.c	Tue Jul 01 15:38:20 2008 +0000
@@ -151,7 +151,11 @@
     }
 
     fmmu = &sc->fmmu_configs[sc->used_fmmus++];
+
+    down(&sc->master->master_sem);
     ec_fmmu_config_init(fmmu, sc, domain, sync_index, dir);
+    up(&sc->master->master_sem);
+
     return fmmu->logical_start_address;
 }
 
@@ -388,11 +392,18 @@
         return -1;
     }
 
-    if (!(pdo = ec_pdo_list_add_pdo(&sc->sync_configs[sync_index].pdos, pdo_index)))
-        return -1;
+    down(&sc->master->master_sem);
+
+    if (!(pdo = ec_pdo_list_add_pdo(&sc->sync_configs[sync_index].pdos,
+                    pdo_index))) {
+        up(&sc->master->master_sem);
+        return -1;
+    }
     pdo->sync_index = sync_index;
 
     ec_slave_config_load_default_mapping(sc, pdo);
+
+    up(&sc->master->master_sem);
     return 0;
 }
 
@@ -410,7 +421,9 @@
         return;
     }
 
+    down(&sc->master->master_sem);
     ec_pdo_list_clear_pdos(&sc->sync_configs[sync_index].pdos);
+    up(&sc->master->master_sem);
 }
 
 /*****************************************************************************/
@@ -421,6 +434,7 @@
 {
     uint8_t sync_index;
     ec_pdo_t *pdo = NULL;
+    int retval = -1;
     
     if (sc->master->debug_level)
         EC_DBG("ecrt_slave_config_pdo_mapping_add(sc = 0x%x, "
@@ -434,14 +448,17 @@
                         &sc->sync_configs[sync_index].pdos, pdo_index)))
             break;
 
-    if (!pdo) {
+    if (pdo) {
+        down(&sc->master->master_sem);
+        retval = ec_pdo_add_entry(pdo, entry_index, entry_subindex,
+                entry_bit_length) ? 0 : -1;
+        up(&sc->master->master_sem);
+    } else {
         EC_ERR("Pdo 0x%04X is not assigned in config %u:%u.\n",
                 pdo_index, sc->alias, sc->position);
-        return -1;
-    }
-
-    return ec_pdo_add_entry(pdo, entry_index, entry_subindex,
-            entry_bit_length) ? 0 : -1;
+    }
+
+    return retval;
 }
 
 /*****************************************************************************/
@@ -461,13 +478,14 @@
                         &sc->sync_configs[sync_index].pdos, pdo_index)))
             break;
 
-    if (!pdo) {
+    if (pdo) {
+        down(&sc->master->master_sem);
+        ec_pdo_clear_entries(pdo);
+        up(&sc->master->master_sem);
+    } else {
         EC_WARN("Pdo 0x%04X is not assigned in config %u:%u.\n",
                 pdo_index, sc->alias, sc->position);
-        return;
-    }
-
-    ec_pdo_clear_entries(pdo);
+    }
 }
 
 /*****************************************************************************/
@@ -563,11 +581,6 @@
                 if (entry->index != index || entry->subindex != subindex) {
                     bit_offset += entry->bit_length;
                 } else {
-                    sync_offset = ec_slave_config_prepare_fmmu(
-                            sc, domain, sync_index, sync_config->dir);
-                    if (sync_offset < 0)
-                        return -2;
-
                     bit_pos = bit_offset % 8;
                     if (bit_position) {
                         *bit_position = bit_pos;
@@ -578,6 +591,11 @@
                         return -3;
                     }
 
+                    sync_offset = ec_slave_config_prepare_fmmu(
+                            sc, domain, sync_index, sync_config->dir);
+                    if (sync_offset < 0)
+                        return -2;
+
                     return sync_offset + bit_offset / 8;
                 }
             }
@@ -618,7 +636,10 @@
         return -1;
     }
         
+    down(&sc->master->master_sem);
     list_add_tail(&req->list, &sc->sdo_configs);
+    up(&sc->master->master_sem);
+
     return 0;
 }
 
@@ -678,7 +699,10 @@
     memset(req->data, 0x00, size);
     req->data_size = size;
     
+    down(&sc->master->master_sem);
     list_add_tail(&req->list, &sc->sdo_requests);
+    up(&sc->master->master_sem);
+
     return req; 
 }