merge -r1583:1593 branches/stable-1.4: Fixed detaching oops.
authorFlorian Pose <fp@igh-essen.com>
Tue, 25 Nov 2008 14:07:19 +0000
changeset 1318 76b4014391bd
parent 1317 09173a2de40c
child 1319 38da03647aee
merge -r1583:1593 branches/stable-1.4: Fixed detaching oops.
NEWS
documentation/graphs/fsm_slave_conf.dot
master/fsm_pdo.c
master/fsm_slave_config.c
master/fsm_slave_config.h
master/sdo_request.c
master/sdo_request.h
--- a/NEWS	Thu Nov 20 12:36:19 2008 +0000
+++ b/NEWS	Tue Nov 25 14:07:19 2008 +0000
@@ -23,6 +23,8 @@
 * Fixed race condition concerning the ec_slave_config_state->operational flag.
 * Fixed wrong calculation of the expected working counter if the process data
   of a domain span several datagrams.
+* Fixed a kernel oops when a slave configuration is detached while the actual
+  configuration is in progress.
 * Fixed typo in logging output.
 
 Changes in 1.4.0-rc3:
--- a/documentation/graphs/fsm_slave_conf.dot	Thu Nov 20 12:36:19 2008 +0000
+++ b/documentation/graphs/fsm_slave_conf.dot	Tue Nov 25 14:07:19 2008 +0000
@@ -5,7 +5,10 @@
     size="3,5"
 
     start [fontname="Helvetica"]
-    start -> init [weight=10]
+    start -> enter_init [weight=10]
+
+    enter_init [shape=point, label=""]
+    enter_init -> init [weight=10]
 
     init [fontname="Helvetica"]
     init -> enter_mbox_sync [fontname="Helvetica", label="No FMMUs"]
@@ -32,12 +35,14 @@
     enter_sdo_conf -> sdo_conf [weight=10]
 
     sdo_conf [fontname="Helvetica"]
+    sdo_conf -> enter_init [fontname="Helvetica", label="Config\ndetached"]
     sdo_conf -> enter_pdo_conf [weight=10]
 
     enter_pdo_conf [shape=point, label=""]
     enter_pdo_conf -> pdo_conf [weight=10]
 
     pdo_conf [fontname="Helvetica"]
+    pdo_conf -> enter_init [fontname="Helvetica", label="Config\ndetached"]
     pdo_conf -> enter_pdo_sync [weight=10]
 
     enter_pdo_sync [shape=point, label=""]
@@ -45,6 +50,7 @@
     enter_pdo_sync -> pdo_sync [weight=10]
 
     pdo_sync [fontname="Helvetica"]
+    pdo_sync -> enter_init [fontname="Helvetica", label="Config\ndetached"]
     pdo_sync -> enter_fmmu [weight=10]
 
     enter_fmmu [shape=point,label=""]
--- a/master/fsm_pdo.c	Thu Nov 20 12:36:19 2008 +0000
+++ b/master/fsm_pdo.c	Tue Nov 25 14:07:19 2008 +0000
@@ -402,6 +402,11 @@
     fsm->sync_index++;
 
     for (; fsm->sync_index < EC_MAX_SYNC_MANAGERS; fsm->sync_index++) {
+        if (!fsm->slave->config) { // slave configuration removed in the meantime
+            fsm->state = ec_fsm_pdo_state_error;
+            return;
+        }
+
         if (ec_pdo_list_copy(&fsm->pdos,
                     &fsm->slave->config->sync_configs[fsm->sync_index].pdos)) {
             fsm->state = ec_fsm_pdo_state_error;
--- a/master/fsm_slave_config.c	Thu Nov 20 12:36:19 2008 +0000
+++ b/master/fsm_slave_config.c	Tue Nov 25 14:07:19 2008 +0000
@@ -58,6 +58,7 @@
 void ec_fsm_slave_config_state_safeop(ec_fsm_slave_config_t *);
 void ec_fsm_slave_config_state_op(ec_fsm_slave_config_t *);
 
+void ec_fsm_slave_config_enter_init(ec_fsm_slave_config_t *);
 void ec_fsm_slave_config_enter_mbox_sync(ec_fsm_slave_config_t *);
 void ec_fsm_slave_config_enter_preop(ec_fsm_slave_config_t *);
 void ec_fsm_slave_config_enter_sdo_conf(ec_fsm_slave_config_t *);
@@ -69,6 +70,8 @@
 void ec_fsm_slave_config_state_end(ec_fsm_slave_config_t *);
 void ec_fsm_slave_config_state_error(ec_fsm_slave_config_t *);
 
+void ec_fsm_slave_config_reconfigure(ec_fsm_slave_config_t *);
+
 /*****************************************************************************/
 
 /** Constructor.
@@ -81,6 +84,8 @@
         ec_fsm_pdo_t *fsm_pdo /**< Pdo configuration state machine to use. */
         )
 {
+    ec_sdo_request_init(&fsm->request_copy);
+
     fsm->datagram = datagram;
     fsm->fsm_change = fsm_change;
     fsm->fsm_coe = fsm_coe;
@@ -95,6 +100,7 @@
         ec_fsm_slave_config_t *fsm /**< slave state machine */
         )
 {
+    ec_sdo_request_clear(&fsm->request_copy);
 }
 
 /*****************************************************************************/
@@ -172,6 +178,17 @@
         EC_DBG("Configuring slave %u...\n", fsm->slave->ring_position);
     }
     
+    ec_fsm_slave_config_enter_init(fsm);
+}
+
+/*****************************************************************************/
+
+/** Start state change to INIT.
+ */
+void ec_fsm_slave_config_enter_init(
+        ec_fsm_slave_config_t *fsm /**< slave state machine */
+        )
+{
     ec_fsm_change_start(fsm->fsm_change, fsm->slave, EC_SLAVE_STATE_INIT);
     ec_fsm_change_exec(fsm->fsm_change);
     fsm->state = ec_fsm_slave_config_state_init;
@@ -444,8 +461,9 @@
     fsm->state = ec_fsm_slave_config_state_sdo_conf;
     fsm->request = list_entry(fsm->slave->config->sdo_configs.next,
             ec_sdo_request_t, list);
-    ecrt_sdo_request_write(fsm->request);
-    ec_fsm_coe_transfer(fsm->fsm_coe, fsm->slave, fsm->request);
+    ec_sdo_request_copy(&fsm->request_copy, fsm->request);
+    ecrt_sdo_request_write(&fsm->request_copy);
+    ec_fsm_coe_transfer(fsm->fsm_coe, fsm->slave, &fsm->request_copy);
     ec_fsm_coe_exec(fsm->fsm_coe); // execute immediately
 }
 
@@ -467,12 +485,18 @@
         return;
     }
 
+    if (!fsm->slave->config) { // config removed in the meantime
+        ec_fsm_slave_config_reconfigure(fsm);
+        return;
+    }
+
     // Another Sdo to configure?
     if (fsm->request->list.next != &fsm->slave->config->sdo_configs) {
-        fsm->request = list_entry(fsm->request->list.next, ec_sdo_request_t,
-                list);
-        ecrt_sdo_request_write(fsm->request);
-        ec_fsm_coe_transfer(fsm->fsm_coe, fsm->slave, fsm->request);
+        fsm->request = list_entry(fsm->request->list.next,
+                ec_sdo_request_t, list);
+        ec_sdo_request_copy(&fsm->request_copy, fsm->request);
+        ecrt_sdo_request_write(&fsm->request_copy);
+        ec_fsm_coe_transfer(fsm->fsm_coe, fsm->slave, &fsm->request_copy);
         ec_fsm_coe_exec(fsm->fsm_coe); // execute immediately
         return;
     }
@@ -506,6 +530,11 @@
     if (ec_fsm_pdo_exec(fsm->fsm_pdo))
         return;
 
+    if (!fsm->slave->config) { // config removed in the meantime
+        ec_fsm_slave_config_reconfigure(fsm);
+        return;
+    }
+
     if (!ec_fsm_pdo_success(fsm->fsm_pdo)) {
         EC_WARN("Pdo configuration failed on slave %u.\n",
                 fsm->slave->ring_position);
@@ -594,6 +623,11 @@
         return;
     }
 
+    if (!fsm->slave->config) { // config removed in the meantime
+        ec_fsm_slave_config_reconfigure(fsm);
+        return;
+    }
+
     ec_fsm_slave_config_enter_fmmu(fsm);
 }
 
@@ -764,6 +798,22 @@
     fsm->state = ec_fsm_slave_config_state_end; // successful
 }
 
+/*****************************************************************************/
+
+/** Reconfigure the slave starting at INIT.
+ */
+void ec_fsm_slave_config_reconfigure(
+        ec_fsm_slave_config_t *fsm /**< slave state machine */
+        )
+{
+    if (fsm->slave->master->debug_level) {
+        EC_DBG("Slave configuration for slave %u detached during "
+                "configuration. Reconfiguring.", fsm->slave->ring_position);
+    }
+
+    ec_fsm_slave_config_enter_init(fsm); // reconfigure
+}
+
 /******************************************************************************
  *  Common state functions
  *****************************************************************************/
--- a/master/fsm_slave_config.h	Thu Nov 20 12:36:19 2008 +0000
+++ b/master/fsm_slave_config.h	Tue Nov 25 14:07:19 2008 +0000
@@ -66,6 +66,7 @@
     void (*state)(ec_fsm_slave_config_t *); /**< State function. */
     unsigned int retries; /**< Retries on datagram timeout. */
     ec_sdo_request_t *request; /**< Sdo request for Sdo configuration. */
+    ec_sdo_request_t request_copy; /**< Copied Sdo request. */
 };
 
 /*****************************************************************************/
--- a/master/sdo_request.c	Thu Nov 20 12:36:19 2008 +0000
+++ b/master/sdo_request.c	Tue Nov 25 14:07:19 2008 +0000
@@ -83,6 +83,22 @@
 
 /*****************************************************************************/
 
+/** Copy another Sdo request.
+ *
+ * \attention Only the index subindex and data are copied.
+ */
+int ec_sdo_request_copy(
+        ec_sdo_request_t *req,
+        const ec_sdo_request_t *other
+        )
+{
+    req->index = other->index;
+    req->subindex = other->subindex;
+    return ec_sdo_request_copy_data(req, other->data, other->data_size);
+}
+
+/*****************************************************************************/
+
 /** Sdo request destructor.
  */
 void ec_sdo_request_clear_data(
--- a/master/sdo_request.h	Thu Nov 20 12:36:19 2008 +0000
+++ b/master/sdo_request.h	Tue Nov 25 14:07:19 2008 +0000
@@ -75,6 +75,7 @@
 void ec_sdo_request_init(ec_sdo_request_t *);
 void ec_sdo_request_clear(ec_sdo_request_t *);
 
+int ec_sdo_request_copy(ec_sdo_request_t *, const ec_sdo_request_t *);
 void ec_sdo_request_address(ec_sdo_request_t *, uint16_t, uint8_t);
 int ec_sdo_request_alloc(ec_sdo_request_t *, size_t);
 int ec_sdo_request_copy_data(ec_sdo_request_t *, const uint8_t *, size_t);