diff --git a/NEWS b/NEWS index aeeb2f15..bcc86da5 100644 --- a/NEWS +++ b/NEWS @@ -8,33 +8,34 @@ Changes in version 1.3.0: * Added testing version of Intel PRO/100 ethernet driver (e100). * Added testing version of NVIDIA nForce ethernet driver (forcedeth). -* Removed "ec_eoeif_count" master module parameter. +* Removed "ec_eoeif_count" master module parameter. EoE handlers are created + dynamically instead. * Added "main" and "backup" parameters to master module to hand over the MAC addresses of the devices to wait for. This made the ec_device_index - parameter of the ethercat drivers obsolete. + parameter of the ethernet drivers obsolete. * Changed format of sysconfig file and accordingly adjusted functionality - of the init script to handle MAC address lists. + of the init script to handle the above MAC address lists. * Realtime interface changes: - ecrt_master_run() became obsolete, because the master state machine is now run in process context. - Parameter changes in PDO registration functions ecrt_domain_register_pdo() and ecrt_register_pdo_range(): Replaced slave_address, vendor ID and - product code arguments with a slave pointer, which has to be optained with + product code arguments with a slave pointer, which has to be obtained with a prior call to ecrt_master_get_slave(). - ecrt_master_get_slave() got additional parameters to check for vendor ID and product code. - Removed addressing scheme "X:Y" for ecrt_master_get_slave(). - - Added ecrt_master_get_status() to get information about the bus. - - Added functions to set up an alternative PDO mapping, i. e. + - Added ecrt_master_get_status() to get status information about the bus. + - Added functions to set up an alternative PDO mapping for a slave, i. e. ec_slave_pdo_mapping_clear(), ec_slave_pdo_mapping_add() and ec_slave_pdo_mapping(). * Device interface changes: - Replaced ecdev_register() and ecdev_unregister() with ecdev_offer() and ecdev_withdraw(), respectively. The device modules now offer all their - devices to the master, which decides, which ones to register. + devices to the master. The master then decides, which ones to register. * All EEPROM write operations from user space are now blocking until - writing has finished and return appropriate error codes. -* Implemented setting of secondary slave address (alias) via sysfs. + writing has finished. Appropriate error codes are returned. +* Implemented setting of the "Secondary slave address" (alias) via sysfs. * Implemented SDO reading in operation mode via sysfs. * Removed annoying eeprom_write_enable file. EEPROM writing always enabled. * Slave configuration is now done exclusively from the master thread. Removed diff --git a/TODO b/TODO index df4e4fa7..4c144d7b 100644 --- a/TODO +++ b/TODO @@ -6,9 +6,6 @@ $Id$ ------------------------------------------------------------------------------- -* Release 1.3: - - Dynamic creation of EoE handlers. - * Future features: - Interface/buffers for asynchronous domain IO. - Distributed clocks. @@ -31,6 +28,7 @@ $Id$ - Interrupt master state machines state scan for other jobs. - Master state machine, slave configuration: Do not check every slave on a cycle. + - Fix problem when lock ist not required for EoE sending. * Less important issues: - Implement all EtherCAT datagram types. diff --git a/master/ethernet.c b/master/ethernet.c index 3cec526f..4fb13d29 100644 --- a/master/ethernet.c +++ b/master/ethernet.c @@ -83,16 +83,21 @@ struct net_device_stats *ec_eoedev_stats(struct net_device *); /*****************************************************************************/ /** - EoE constructor. - Initializes the EoE handler, creates a net_device and registeres it. -*/ + * EoE constructor. + * Initializes the EoE handler, creates a net_device and registers it. + */ -int ec_eoe_init(ec_eoe_t *eoe /**< EoE handler */) +int ec_eoe_init( + ec_eoe_t *eoe, /**< EoE handler */ + ec_slave_t *slave /**< EtherCAT slave */ + ) { ec_eoe_t **priv; int result, i; + char name[20]; + + eoe->slave = slave; - eoe->slave = NULL; ec_datagram_init(&eoe->datagram); eoe->state = ec_eoe_state_rx_start; eoe->opened = 0; @@ -112,8 +117,9 @@ int ec_eoe_init(ec_eoe_t *eoe /**< EoE handler */) eoe->tx_rate = 0; eoe->rate_jiffies = 0; - if (!(eoe->dev = - alloc_netdev(sizeof(ec_eoe_t *), "eoe%d", ether_setup))) { + sprintf(name, "eoe%u-%u", slave->master->index, slave->ring_position); + + if (!(eoe->dev = alloc_netdev(sizeof(ec_eoe_t *), name, ether_setup))) { EC_ERR("Unable to allocate net_device for EoE handler!\n"); goto out_return; } @@ -147,7 +153,6 @@ int ec_eoe_init(ec_eoe_t *eoe /**< EoE handler */) // make the last address octet unique eoe->dev->dev_addr[ETH_ALEN - 1] = (uint8_t) eoe->dev->ifindex; - return 0; out_free: @@ -305,9 +310,9 @@ void ec_eoe_run(ec_eoe_t *eoe /**< EoE handler */) \return 1 if the device is "up", 0 if it is "down" */ -int ec_eoe_active(const ec_eoe_t *eoe /**< EoE handler */) +int ec_eoe_is_open(const ec_eoe_t *eoe /**< EoE handler */) { - return eoe->slave && eoe->opened; + return eoe->opened; } /****************************************************************************** diff --git a/master/ethernet.h b/master/ethernet.h index cd7f5c25..c0f32847 100644 --- a/master/ethernet.h +++ b/master/ethernet.h @@ -99,9 +99,9 @@ struct ec_eoe /*****************************************************************************/ -int ec_eoe_init(ec_eoe_t *); +int ec_eoe_init(ec_eoe_t *, ec_slave_t *); void ec_eoe_clear(ec_eoe_t *); void ec_eoe_run(ec_eoe_t *); -int ec_eoe_active(const ec_eoe_t *); +int ec_eoe_is_open(const ec_eoe_t *); /*****************************************************************************/ diff --git a/master/fsm_master.c b/master/fsm_master.c index 80af7d02..4fd3f61d 100644 --- a/master/fsm_master.c +++ b/master/fsm_master.c @@ -41,6 +41,7 @@ #include "globals.h" #include "master.h" #include "mailbox.h" +#include "ethernet.h" #include "fsm_master.h" /*****************************************************************************/ @@ -238,6 +239,7 @@ void ec_fsm_master_state_broadcast(ec_fsm_master_t *fsm /**< master state machin fsm->scan_jiffies = jiffies; ec_master_eoe_stop(master); + ec_master_clear_eoe_handlers(master); ec_master_destroy_slaves(master); master->slave_count = datagram->working_counter; @@ -483,9 +485,6 @@ void ec_fsm_master_action_process_states(ec_fsm_master_t *fsm return; } - // Check, if EoE processing has to be started - ec_master_eoe_start(master); - // Check for a pending SDO request if (ec_fsm_master_action_process_sdo(fsm)) return; @@ -809,6 +808,23 @@ void ec_fsm_master_state_scan_slaves( if (ec_fsm_slave_exec(&fsm->fsm_slave)) // execute slave state machine return; + if (slave->sii_mailbox_protocols & EC_MBOX_EOE) { + // create EoE handler for this slave + ec_eoe_t *eoe; + if (!(eoe = kmalloc(sizeof(ec_eoe_t), GFP_KERNEL))) { + EC_ERR("Failed to allocate EoE handler memory for slave %u!\n", + slave->ring_position); + } + else if (ec_eoe_init(eoe, slave)) { + EC_ERR("Failed to init EoE handler for slave %u!\n", + slave->ring_position); + kfree(eoe); + } + else { + list_add_tail(&eoe->list, &master->eoe_handlers); + } + } + // another slave to fetch? if (slave->list.next != &master->slaves) { fsm->slave = list_entry(slave->list.next, ec_slave_t, list); @@ -819,6 +835,10 @@ void ec_fsm_master_state_scan_slaves( EC_INFO("Bus scanning completed in %u ms.\n", (u32) (jiffies - fsm->scan_jiffies) * 1000 / HZ); + + // check if EoE processing has to be started + ec_master_eoe_start(master); + master->scan_state = EC_REQUEST_COMPLETE; wake_up_interruptible(&master->scan_queue); diff --git a/master/master.c b/master/master.c index 67df6e7a..0338a7c0 100644 --- a/master/master.c +++ b/master/master.c @@ -154,7 +154,6 @@ int ec_master_init(ec_master_t *master, /**< EtherCAT master */ master->eoe_timer.function = ec_master_eoe_run; master->eoe_timer.data = (unsigned long) master; master->eoe_running = 0; - master->eoe_checked = 0; INIT_LIST_HEAD(&master->eoe_handlers); master->internal_lock = SPIN_LOCK_UNLOCKED; @@ -229,40 +228,36 @@ void ec_master_clear( ec_master_t *master /**< EtherCAT master */ ) { - ec_eoe_t *eoe, *next_eoe; - ec_datagram_t *datagram, *next_datagram; - + ec_master_clear_eoe_handlers(master); ec_master_destroy_slaves(master); ec_master_destroy_domains(master); - - // list of EEPROM requests is empty, - // otherwise master could not be cleared. - - // dequeue all datagrams - list_for_each_entry_safe(datagram, next_datagram, - &master->datagram_queue, queue) { - datagram->state = EC_DATAGRAM_ERROR; - list_del_init(&datagram->queue); - } - ec_fsm_master_clear(&master->fsm); ec_datagram_clear(&master->fsm_datagram); - - // 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); - } - ec_device_clear(&master->backup_device); ec_device_clear(&master->main_device); // destroy self kobject_del(&master->kobj); kobject_put(&master->kobj); +} - EC_INFO("Master %u freed.\n", master->index); +/*****************************************************************************/ + +/** + * Clear and free all EoE handlers. + */ + +void ec_master_clear_eoe_handlers( + ec_master_t *master /**< EtherCAT master */ + ) +{ + ec_eoe_t *eoe, *next; + + list_for_each_entry_safe(eoe, next, &master->eoe_handlers, list) { + list_del(&eoe->list); + ec_eoe_clear(eoe); + kfree(eoe); + } } /*****************************************************************************/ @@ -413,6 +408,7 @@ void ec_master_leave_idle_mode(ec_master_t *master /**< EtherCAT master */) int ec_master_enter_operation_mode(ec_master_t *master /**< EtherCAT master */) { ec_slave_t *slave; + ec_eoe_t *eoe; down(&master->config_sem); master->allow_config = 0; // temporarily disable slave configuration @@ -446,12 +442,20 @@ int ec_master_enter_operation_mode(ec_master_t *master /**< EtherCAT master */) list_for_each_entry(slave, &master->slaves, list) { ec_slave_request_state(slave, EC_SLAVE_STATE_PREOP); } + // ... but set EoE slaves to OP + list_for_each_entry(eoe, &master->eoe_handlers, list) { + if (ec_eoe_is_open(eoe)) + ec_slave_request_state(eoe->slave, EC_SLAVE_STATE_OP); + } if (master->debug_level) EC_DBG("Switching to operation mode.\n"); master->mode = EC_MASTER_MODE_OPERATION; master->pdo_slaves_offline = 0; // assume all PDO slaves online + master->ext_request_cb = NULL; + master->ext_release_cb = NULL; + master->ext_cb_data = NULL; return 0; out_allow: @@ -470,6 +474,7 @@ void ec_master_leave_operation_mode(ec_master_t *master /**< EtherCAT master */) { ec_slave_t *slave; + ec_eoe_t *eoe; master->mode = EC_MASTER_MODE_IDLE; @@ -485,15 +490,20 @@ void ec_master_leave_operation_mode(ec_master_t *master ec_slave_reset(slave); ec_slave_request_state(slave, EC_SLAVE_STATE_PREOP); } + // ... but leave EoE slaves in OP + list_for_each_entry(eoe, &master->eoe_handlers, list) { + if (ec_eoe_is_open(eoe)) + ec_slave_request_state(eoe->slave, EC_SLAVE_STATE_OP); + } ec_master_destroy_domains(master); + if (ec_master_thread_start(master, ec_master_idle_thread)) + EC_WARN("Failed to restart master thread!\n"); + ec_master_eoe_start(master); + master->allow_scan = 1; master->allow_config = 1; - - if (ec_master_thread_start(master, ec_master_idle_thread)) { - EC_WARN("Failed to restart master thread!\n"); - } } /*****************************************************************************/ @@ -1059,48 +1069,16 @@ ssize_t ec_store_master_attribute(struct kobject *kobj, /**< slave's kobject */ 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 || master->eoe_checked) return; - - master->eoe_checked = 1; - - // decouple all EoE handlers - list_for_each_entry(eoe, &master->eoe_handlers, list) - eoe->slave = NULL; - - // couple a free EoE handler to every EoE-capable slave - coupled = 0; - 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) - ec_slave_request_state(slave, EC_SLAVE_STATE_OP); - else - ec_slave_request_state(slave, EC_SLAVE_STATE_PREOP); - break; - } - - if (!found) { - if (master->debug_level) - EC_WARN("No EoE handler for slave %i!\n", - slave->ring_position); - ec_slave_request_state(slave, EC_SLAVE_STATE_PREOP); - } + if (master->eoe_running) { + EC_WARN("EoE already running!\n"); + return; } - if (!coupled) { - EC_INFO("No EoE handlers coupled.\n"); + if (list_empty(&master->eoe_handlers)) + return; + + if (!master->request_cb || !master->release_cb) { + EC_WARN("No EoE processing because of missing locking callbacks!\n"); return; } @@ -1110,7 +1088,6 @@ void ec_master_eoe_start(ec_master_t *master /**< EtherCAT master */) // start EoE processing master->eoe_timer.expires = jiffies + 10; add_timer(&master->eoe_timer); - return; } /*****************************************************************************/ @@ -1121,24 +1098,11 @@ void ec_master_eoe_start(ec_master_t *master /**< EtherCAT master */) void ec_master_eoe_stop(ec_master_t *master /**< EtherCAT master */) { - ec_eoe_t *eoe; - - master->eoe_checked = 0; - 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) { - ec_slave_request_state(eoe->slave, EC_SLAVE_STATE_PREOP); - eoe->slave = NULL; - } - } - master->eoe_running = 0; } @@ -1152,14 +1116,18 @@ 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; + unsigned int none_open = 1; cycles_t cycles_start, cycles_end; unsigned long restart_jiffies; list_for_each_entry(eoe, &master->eoe_handlers, list) { - if (ec_eoe_active(eoe)) active++; + if (ec_eoe_is_open(eoe)) { + none_open = 0; + break; + } } - if (!active) goto queue_timer; + if (none_open) + goto queue_timer; // receive datagrams if (master->request_cb(master->cb_data)) goto queue_timer; @@ -1288,12 +1256,11 @@ void ec_master_prepare(ec_master_t *master /**< EtherCAT master */) /** * Translates an ASCII coded bus-address to a slave pointer. * These are the valid addressing schemes: - * - \a "X" = the X. slave on the bus (ring position), - * - \a "X:Y" = the Y. slave after the X. branch (bus coupler), + * - \a "X" = the Xth slave on the bus (ring position), * - \a "#X" = the slave with alias X, - * - \a "#X:Y" = the Y. slave after the branch (bus coupler) with alias X. + * - \a "#X:Y" = the Yth slave after the slave with alias X. * X and Y are zero-based indices and may be provided in hexadecimal or octal - * notation (with respective prefix). + * notation (with appropriate prefix). * \return pointer to the slave on success, else NULL */ @@ -1462,12 +1429,15 @@ int ecrt_master_activate(ec_master_t *master /**< EtherCAT master */) master->injection_seq_fsm = 0; master->injection_seq_rt = 0; + master->request_cb = master->ext_request_cb; + master->release_cb = master->ext_release_cb; + master->cb_data = master->ext_cb_data; if (ec_master_thread_start(master, ec_master_operation_thread)) { EC_ERR("Failed to start master thread!\n"); return -1; } - + ec_master_eoe_start(master); return 0; } @@ -1577,9 +1547,9 @@ void ecrt_master_callbacks(ec_master_t *master, /**< EtherCAT master */ void *cb_data /**< data parameter */ ) { - master->request_cb = request_cb; - master->release_cb = release_cb; - master->cb_data = cb_data; + master->ext_request_cb = request_cb; + master->ext_release_cb = release_cb; + master->ext_cb_data = cb_data; } /*****************************************************************************/ diff --git a/master/master.h b/master/master.h index cb787113..9d7d2397 100644 --- a/master/master.h +++ b/master/master.h @@ -144,17 +144,18 @@ struct ec_master unsigned int idle_cycle_time_pos; /**< time ring buffer position */ struct timer_list eoe_timer; /**< EoE timer object */ + unsigned int eoe_running; /**< non-zero, if EoE processing is active. */ + struct list_head eoe_handlers; /**< Ethernet-over-EtherCAT handlers */ uint32_t eoe_cycle_times[HZ]; /**< EoE cycle times ring */ unsigned int eoe_cycle_time_pos; /**< time ring buffer position */ - unsigned int eoe_running; /**< non-zero, if EoE processing is active. */ - unsigned int eoe_checked; /**< non-zero, if EoE processing is not - necessary. */ - struct list_head eoe_handlers; /**< Ethernet-over-EtherCAT handlers */ spinlock_t internal_lock; /**< spinlock used in idle mode */ int (*request_cb)(void *); /**< lock request callback */ void (*release_cb)(void *); /**< lock release callback */ void *cb_data; /**< data parameter of locking callbacks */ + int (*ext_request_cb)(void *); /**< external lock request callback */ + void (*ext_release_cb)(void *); /**< externam lock release callback */ + void *ext_cb_data; /**< data parameter of external locking callbacks */ struct list_head eeprom_requests; /**< EEPROM write requests */ struct semaphore eeprom_sem; /**< semaphore protecting the list of @@ -192,6 +193,7 @@ void ec_master_queue_datagram(ec_master_t *, ec_datagram_t *); // misc. void ec_master_output_stats(ec_master_t *); +void ec_master_clear_eoe_handlers(ec_master_t *); void ec_master_destroy_slaves(ec_master_t *); /*****************************************************************************/