From 61d6eea4e94987ee26a76ee93ea20eae3e1a8221 Mon Sep 17 00:00:00 2001 From: Florian Pose <fp@igh-essen.com> Date: Tue, 1 Jul 2008 15:38:20 +0000 Subject: [PATCH] Implemented master semaphore to secure concurrent access from ioctls, state machine and realtime interface. --- master/cdev.c | 5 +++-- master/domain.c | 4 ++++ master/master.c | 34 ++++++++++++++++++++++------ master/master.h | 1 + master/slave_config.c | 52 +++++++++++++++++++++++++++++++------------ 5 files changed, 73 insertions(+), 23 deletions(-) diff --git a/master/cdev.c b/master/cdev.c index 7f6dbf6e..7607f8f5 100644 --- a/master/cdev.c +++ b/master/cdev.c @@ -138,8 +138,8 @@ long eccdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 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 @@ long eccdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -ENOTTY; } + up(&master->master_sem); return retval; } diff --git a/master/domain.c b/master/domain.c index 06d90464..b382cce5 100644 --- a/master/domain.c +++ b/master/domain.c @@ -344,10 +344,14 @@ size_t ecrt_domain_size(ec_domain_t *domain) 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); } /*****************************************************************************/ diff --git a/master/master.c b/master/master.c index de38a9d1..fdf9d88a 100644 --- a/master/master.c +++ b/master/master.c @@ -85,6 +85,8 @@ int ec_master_init(ec_master_t *master, /**< EtherCAT master */ 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 @@ int ec_master_enter_idle_phase( 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 @@ void ec_master_leave_idle_phase(ec_master_t *master /**< EtherCAT master */) 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 @@ int ec_master_enter_operation_phase(ec_master_t *master /**< EtherCAT master */) } #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 @@ void ec_master_leave_operation_phase(ec_master_t *master 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 @@ static int ec_master_idle_thread(ec_master_t *master) 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 @@ static int ec_master_operation_thread(ec_master_t *master) 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 @@ ec_domain_t *ecrt_master_create_domain(ec_master_t *master /**< master */) return NULL; } + down(&master->master_sem); + if (list_empty(&master->domains)) { index = 0; } else { @@ -1156,6 +1166,8 @@ ec_domain_t *ecrt_master_create_domain(ec_master_t *master /**< master */) ec_domain_init(domain, master, index); list_add_tail(&domain->list, &master->domains); + up(&master->master_sem); + return domain; } @@ -1166,6 +1178,8 @@ int ecrt_master_activate(ec_master_t *master) 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 @@ int ecrt_master_activate(ec_master_t *master) } 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_t *ecrt_master_slave_config(ec_master_t *master, 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; diff --git a/master/master.h b/master/master.h index 19c61568..7d24d765 100644 --- a/master/master.h +++ b/master/master.h @@ -88,6 +88,7 @@ struct ec_master { 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. */ diff --git a/master/slave_config.c b/master/slave_config.c index 83b5ff34..dd73366e 100644 --- a/master/slave_config.c +++ b/master/slave_config.c @@ -151,7 +151,11 @@ int ec_slave_config_prepare_fmmu( } 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 @@ int ecrt_slave_config_pdo_assign_add(ec_slave_config_t *sc, return -1; } - if (!(pdo = ec_pdo_list_add_pdo(&sc->sync_configs[sync_index].pdos, pdo_index))) + 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 @@ void ecrt_slave_config_pdo_assign_clear(ec_slave_config_t *sc, 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 @@ int ecrt_slave_config_pdo_mapping_add(ec_slave_config_t *sc, { 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 @@ int ecrt_slave_config_pdo_mapping_add(ec_slave_config_t *sc, &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 @@ void ecrt_slave_config_pdo_mapping_clear(ec_slave_config_t *sc, &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 @@ int ecrt_slave_config_reg_pdo_entry( 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 @@ int ecrt_slave_config_reg_pdo_entry( 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 @@ int ecrt_slave_config_sdo(ec_slave_config_t *sc, uint16_t index, 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 @@ ec_sdo_request_t *ecrt_slave_config_create_sdo_request(ec_slave_config_t *sc, 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; } -- GitLab