Implemented master semaphore to secure concurrent access from ioctls, state machine and realtime interface.
This commit is contained in:
parent
131bcd7203
commit
d942e87cef
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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. */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue