Dynamic creation of EoE handlers.
authorFlorian Pose <fp@igh-essen.com>
Fri, 16 Mar 2007 14:00:12 +0000
changeset 661 bc1de1362efb
parent 660 582a90a34303
child 662 9b9eaacbd71f
Dynamic creation of EoE handlers.
NEWS
TODO
master/ethernet.c
master/ethernet.h
master/fsm_master.c
master/master.c
master/master.h
--- a/NEWS	Fri Mar 16 13:39:19 2007 +0000
+++ b/NEWS	Fri Mar 16 14:00:12 2007 +0000
@@ -8,33 +8,34 @@
 
 * 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
--- a/TODO	Fri Mar 16 13:39:19 2007 +0000
+++ b/TODO	Fri Mar 16 14:00:12 2007 +0000
@@ -6,9 +6,6 @@
 
 -------------------------------------------------------------------------------
 
-* Release 1.3:
-  - Dynamic creation of EoE handlers.
-
 * Future features:
   - Interface/buffers for asynchronous domain IO.
   - Distributed clocks.
@@ -31,6 +28,7 @@
   - 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.
--- a/master/ethernet.c	Fri Mar 16 13:39:19 2007 +0000
+++ b/master/ethernet.c	Fri Mar 16 14:00:12 2007 +0000
@@ -83,16 +83,21 @@
 /*****************************************************************************/
 
 /**
-   EoE constructor.
-   Initializes the EoE handler, creates a net_device and registeres it.
-*/
-
-int ec_eoe_init(ec_eoe_t *eoe /**< EoE handler */)
+ * EoE constructor.
+ * Initializes the EoE handler, creates a net_device and registers it.
+ */
+
+int ec_eoe_init(
+        ec_eoe_t *eoe, /**< EoE handler */
+        ec_slave_t *slave /**< EtherCAT slave */
+        )
 {
     ec_eoe_t **priv;
     int result, i;
-
-    eoe->slave = NULL;
+    char name[20];
+
+    eoe->slave = slave;
+
     ec_datagram_init(&eoe->datagram);
     eoe->state = ec_eoe_state_rx_start;
     eoe->opened = 0;
@@ -112,8 +117,9 @@
     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 @@
 
     // 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 @@
    \return 1 if the device is "up", 0 if it is "down"
 */
 
-int ec_eoe_active(const ec_eoe_t *eoe /**< EoE handler */)
-{
-    return eoe->slave && eoe->opened;
+int ec_eoe_is_open(const ec_eoe_t *eoe /**< EoE handler */)
+{
+    return eoe->opened;
 }
 
 /******************************************************************************
--- a/master/ethernet.h	Fri Mar 16 13:39:19 2007 +0000
+++ b/master/ethernet.h	Fri Mar 16 14:00:12 2007 +0000
@@ -99,9 +99,9 @@
 
 /*****************************************************************************/
 
-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 *);
 
 /*****************************************************************************/
--- a/master/fsm_master.c	Fri Mar 16 13:39:19 2007 +0000
+++ b/master/fsm_master.c	Fri Mar 16 14:00:12 2007 +0000
@@ -41,6 +41,7 @@
 #include "globals.h"
 #include "master.h"
 #include "mailbox.h"
+#include "ethernet.h"
 #include "fsm_master.h"
 
 /*****************************************************************************/
@@ -238,6 +239,7 @@
             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 @@
             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 @@
     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 @@
 
     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);
 
--- a/master/master.c	Fri Mar 16 13:39:19 2007 +0000
+++ b/master/master.c	Fri Mar 16 14:00:12 2007 +0000
@@ -154,7 +154,6 @@
     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 @@
         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) {
+    ec_device_clear(&master->backup_device);
+    ec_device_clear(&master->main_device);
+
+    // destroy self
+    kobject_del(&master->kobj);
+    kobject_put(&master->kobj);
+}
+
+/*****************************************************************************/
+
+/**
+ * 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);
     }
-
-    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);
 }
 
 /*****************************************************************************/
@@ -413,6 +408,7 @@
 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 @@
     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 @@
                                     /**< EtherCAT master */)
 {
     ec_slave_t *slave;
+    ec_eoe_t *eoe;
 
     master->mode = EC_MASTER_MODE_IDLE;
 
@@ -485,15 +490,20 @@
         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 @@
 
 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 (!coupled) {
-        EC_INFO("No EoE handlers coupled.\n");
+    if (master->eoe_running) {
+        EC_WARN("EoE already running!\n");
+        return;
+    }
+
+    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 @@
     // start EoE processing
     master->eoe_timer.expires = jiffies + 10;
     add_timer(&master->eoe_timer);
-    return;
 }
 
 /*****************************************************************************/
@@ -1121,24 +1098,11 @@
 
 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 @@
 {
     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 (!active) goto queue_timer;
+        if (ec_eoe_is_open(eoe)) {
+            none_open = 0;
+            break;
+        }
+    }
+    if (none_open)
+        goto queue_timer;
 
     // receive datagrams
     if (master->request_cb(master->cb_data)) goto queue_timer;
@@ -1288,12 +1256,11 @@
 /**
  * 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 @@
 
     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 *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;
 }
 
 /*****************************************************************************/
--- a/master/master.h	Fri Mar 16 13:39:19 2007 +0000
+++ b/master/master.h	Fri Mar 16 14:00:12 2007 +0000
@@ -144,17 +144,18 @@
     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 @@
 
 // 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 *);
 
 /*****************************************************************************/