diff -r 440ae5f6d2c3 -r c1d0b63a9302 master/master.c --- a/master/master.c Fri May 19 09:56:55 2006 +0000 +++ b/master/master.c Fri May 19 13:23:11 2006 +0000 @@ -56,7 +56,7 @@ /*****************************************************************************/ void ec_master_freerun(void *); -void ec_master_run_eoe(unsigned long); +void ec_master_eoe_run(unsigned long); ssize_t ec_show_master_attribute(struct kobject *, struct attribute *, char *); void ec_master_process_watch_command(ec_master_t *); @@ -94,30 +94,51 @@ */ int ec_master_init(ec_master_t *master, /**< EtherCAT master */ - unsigned int index /**< master index */ + unsigned int index, /**< master index */ + unsigned int eoe_devices /**< number of EoE devices */ ) { + ec_eoe_t *eoe, *next_eoe; + unsigned int i; + EC_INFO("Initializing master %i.\n", index); - if (!(master->workqueue = create_singlethread_workqueue("EoE"))) { - EC_ERR("Failed to create master workqueue.\n"); - goto out_return; - } - - if (ec_fsm_init(&master->fsm, master)) goto out_free_wq; - master->index = index; master->device = NULL; master->reserved = 0; INIT_LIST_HEAD(&master->slaves); INIT_LIST_HEAD(&master->command_queue); INIT_LIST_HEAD(&master->domains); - INIT_LIST_HEAD(&master->eoe_slaves); + INIT_LIST_HEAD(&master->eoe_handlers); ec_command_init(&master->simple_command); INIT_WORK(&master->freerun_work, ec_master_freerun, (void *) master); init_timer(&master->eoe_timer); - master->eoe_timer.function = ec_master_run_eoe; + master->eoe_timer.function = ec_master_eoe_run; master->eoe_timer.data = (unsigned long) master; + master->internal_lock = SPIN_LOCK_UNLOCKED; + master->eoe_running = 0; + + // create workqueue + if (!(master->workqueue = create_singlethread_workqueue("EtherCAT"))) { + EC_ERR("Failed to create master workqueue.\n"); + goto out_return; + } + + // create EoE handlers + for (i = 0; i < eoe_devices; i++) { + if (!(eoe = (ec_eoe_t *) kmalloc(sizeof(ec_eoe_t), GFP_KERNEL))) { + EC_ERR("Failed to allocate EoE-Object.\n"); + goto out_clear_eoe; + } + if (ec_eoe_init(eoe)) { + kfree(eoe); + goto out_clear_eoe; + } + list_add_tail(&eoe->list, &master->eoe_handlers); + } + + // create state machine object + if (ec_fsm_init(&master->fsm, master)) goto out_clear_eoe; // init kobject and add it to the hierarchy memset(&master->kobj, 0x00, sizeof(struct kobject)); @@ -132,7 +153,12 @@ ec_master_reset(master); return 0; - out_free_wq: + out_clear_eoe: + list_for_each_entry_safe(eoe, next_eoe, &master->eoe_handlers, list) { + list_del(&eoe->list); + ec_eoe_clear(eoe); + kfree(eoe); + } destroy_workqueue(master->workqueue); out_return: return -1; @@ -149,6 +175,7 @@ void ec_master_clear(struct kobject *kobj /**< kobject of the master */) { ec_master_t *master = container_of(kobj, ec_master_t, kobj); + ec_eoe_t *eoe, *next_eoe; EC_INFO("Clearing master %i...\n", master->index); @@ -157,6 +184,13 @@ ec_command_clear(&master->simple_command); destroy_workqueue(master->workqueue); + // clear EoE objects + list_for_each_entry_safe(eoe, next_eoe, &master->eoe_handlers, list) { + list_del(&eoe->list); + ec_eoe_clear(eoe); + kfree(eoe); + } + if (master->device) { ec_device_clear(master->device); kfree(master->device); @@ -177,14 +211,9 @@ { ec_command_t *command, *next_c; ec_domain_t *domain, *next_d; - ec_eoe_t *eoe, *next_eoe; - - // stop EoE processing - del_timer_sync(&master->eoe_timer); - - // stop free-run mode + + ec_master_eoe_stop(master); ec_master_freerun_stop(master); - ec_master_clear_slaves(master); // empty command queue @@ -200,13 +229,6 @@ kobject_put(&domain->kobj); } - // clear EoE objects - list_for_each_entry_safe(eoe, next_eoe, &master->eoe_slaves, list) { - list_del(&eoe->list); - ec_eoe_clear(eoe); - kfree(eoe); - } - master->command_index = 0; master->debug_level = 0; master->timeout = 500; // 500us @@ -674,6 +696,8 @@ { if (master->mode != EC_MASTER_MODE_FREERUN) return; + ec_master_eoe_stop(master); + EC_INFO("Stopping Free-Run mode.\n"); if (!cancel_delayed_work(&master->freerun_work)) { @@ -693,18 +717,21 @@ void ec_master_freerun(void *data /**< master pointer */) { ec_master_t *master = (ec_master_t *) data; - unsigned long delay; + + // aquire master lock + spin_lock_bh(&master->internal_lock); ecrt_master_async_receive(master); - // execute freerun state machine + // execute master state machine ec_fsm_execute(&master->fsm); ecrt_master_async_send(master); - delay = HZ / 100; - if (ec_fsm_idle(&master->fsm)) delay = HZ; - queue_delayed_work(master->workqueue, &master->freerun_work, delay); + // release master lock + spin_unlock_bh(&master->internal_lock); + + queue_delayed_work(master->workqueue, &master->freerun_work, HZ / 100); } /*****************************************************************************/ @@ -799,31 +826,130 @@ /*****************************************************************************/ /** + Starts Ethernet-over-EtherCAT processing for all EoE-capable slaves. +*/ + +void ec_master_eoe_start(ec_master_t *master /**< EtherCAT master */) +{ + ec_eoe_t *eoe; + ec_slave_t *slave; + unsigned int coupled, found; + + if (master->eoe_running) return; + + // decouple all EoE handlers + list_for_each_entry(eoe, &master->eoe_handlers, list) + eoe->slave = NULL; + coupled = 0; + + // couple a free EoE handler to every EoE-capable slave + list_for_each_entry(slave, &master->slaves, list) { + if (!(slave->sii_mailbox_protocols & EC_MBOX_EOE)) continue; + + found = 0; + list_for_each_entry(eoe, &master->eoe_handlers, list) { + if (eoe->slave) continue; + eoe->slave = slave; + found = 1; + coupled++; + EC_INFO("Coupling device %s to slave %i.\n", + eoe->dev->name, slave->ring_position); + if (eoe->opened) + slave->requested_state = EC_SLAVE_STATE_OP; + } + + if (!found) { + EC_WARN("No EoE handler for slave %i!\n", slave->ring_position); + slave->requested_state = EC_SLAVE_STATE_INIT; + } + } + + if (!coupled) { + EC_INFO("No EoE handlers coupled.\n"); + return; + } + + EC_INFO("Starting EoE processing.\n"); + master->eoe_running = 1; + + // start EoE processing + master->eoe_timer.expires = jiffies + 10; + add_timer(&master->eoe_timer); + return; +} + +/*****************************************************************************/ + +/** + Stops the Ethernet-over-EtherCAT processing. +*/ + +void ec_master_eoe_stop(ec_master_t *master /**< EtherCAT master */) +{ + ec_eoe_t *eoe; + + if (!master->eoe_running) return; + + EC_INFO("Stopping EoE processing.\n"); + + del_timer_sync(&master->eoe_timer); + + // decouple all EoE handlers + list_for_each_entry(eoe, &master->eoe_handlers, list) { + if (eoe->slave) { + eoe->slave->requested_state = EC_SLAVE_STATE_INIT; + eoe->slave = NULL; + } + } + + master->eoe_running = 0; +} + +/*****************************************************************************/ + +/** Does the Ethernet-over-EtherCAT processing. */ -void ec_master_run_eoe(unsigned long data /**< master pointer */) +void ec_master_eoe_run(unsigned long data /**< master pointer */) { ec_master_t *master = (ec_master_t *) data; ec_eoe_t *eoe; unsigned int active = 0; - list_for_each_entry(eoe, &master->eoe_slaves, list) { + list_for_each_entry(eoe, &master->eoe_handlers, list) { if (ec_eoe_active(eoe)) active++; } - - // request_cb must return 0, if the lock has been aquired! - if (active && !master->request_cb(master->cb_data)) - { - ecrt_master_async_receive(master); - list_for_each_entry(eoe, &master->eoe_slaves, list) { - ec_eoe_run(eoe); - } - ecrt_master_async_send(master); - + if (!active) goto queue_timer; + + // aquire master lock... + if (master->mode == EC_MASTER_MODE_RUNNING) { + // request_cb must return 0, if the lock has been aquired! + if (master->request_cb(master->cb_data)) + goto queue_timer; + } + else if (master->mode == EC_MASTER_MODE_FREERUN) { + spin_lock(&master->internal_lock); + } + else + goto queue_timer; + + // actual EoE stuff + ecrt_master_async_receive(master); + list_for_each_entry(eoe, &master->eoe_handlers, list) { + ec_eoe_run(eoe); + } + ecrt_master_async_send(master); + + // release lock... + if (master->mode == EC_MASTER_MODE_RUNNING) { master->release_cb(master->cb_data); } - + else if (master->mode == EC_MASTER_MODE_FREERUN) { + spin_unlock(&master->internal_lock); + } + + queue_timer: master->eoe_timer.expires += HZ / EC_EOE_FREQUENCY; add_timer(&master->eoe_timer); } @@ -1404,37 +1530,12 @@ int ecrt_master_start_eoe(ec_master_t *master /**< EtherCAT master */) { - ec_eoe_t *eoe; - ec_slave_t *slave; - if (!master->request_cb || !master->release_cb) { EC_ERR("EoE requires master callbacks to be set!\n"); return -1; } - list_for_each_entry(slave, &master->slaves, list) { - // does the slave support EoE? - if (!(slave->sii_mailbox_protocols & EC_MBOX_EOE)) continue; - - if (!(eoe = (ec_eoe_t *) kmalloc(sizeof(ec_eoe_t), GFP_KERNEL))) { - EC_ERR("Failed to allocate EoE-Object.\n"); - return -1; - } - if (ec_eoe_init(eoe, slave)) { - kfree(eoe); - return -1; - } - list_add_tail(&eoe->list, &master->eoe_slaves); - } - - if (list_empty(&master->eoe_slaves)) { - EC_WARN("start_eoe: no EoE-capable slaves present.\n"); - return 0; - } - - // start EoE processing - master->eoe_timer.expires = jiffies + 10; - add_timer(&master->eoe_timer); + ec_master_eoe_start(master); return 0; } @@ -1482,9 +1583,9 @@ list_for_each_entry(slave, &master->slaves, list) ec_slave_print(slave, verbosity); } - if (!list_empty(&master->eoe_slaves)) { + if (!list_empty(&master->eoe_handlers)) { EC_INFO("Ethernet-over-EtherCAT (EoE) objects:\n"); - list_for_each_entry(eoe, &master->eoe_slaves, list) { + list_for_each_entry(eoe, &master->eoe_handlers, list) { ec_eoe_print(eoe); } }