From c66d1cc62ac47b58931afc62bfdedd285fb315f0 Mon Sep 17 00:00:00 2001 From: Florian Pose Date: Tue, 25 Nov 2008 14:07:19 +0000 Subject: [PATCH] merge -r1583:1593 branches/stable-1.4: Fixed detaching oops. --- NEWS | 2 + documentation/graphs/fsm_slave_conf.dot | 8 +++- master/fsm_pdo.c | 5 ++ master/fsm_slave_config.c | 62 ++++++++++++++++++++++--- master/fsm_slave_config.h | 1 + master/sdo_request.c | 16 +++++++ master/sdo_request.h | 1 + 7 files changed, 88 insertions(+), 7 deletions(-) diff --git a/NEWS b/NEWS index c261014c..267305ba 100644 --- a/NEWS +++ b/NEWS @@ -23,6 +23,8 @@ Changes since 1.4.0-rc3: * 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: diff --git a/documentation/graphs/fsm_slave_conf.dot b/documentation/graphs/fsm_slave_conf.dot index d7ee382f..8ed4a345 100644 --- a/documentation/graphs/fsm_slave_conf.dot +++ b/documentation/graphs/fsm_slave_conf.dot @@ -5,7 +5,10 @@ digraph slaveconf { 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 @@ digraph slaveconf { 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 @@ digraph slaveconf { 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=""] diff --git a/master/fsm_pdo.c b/master/fsm_pdo.c index f7cd5a82..08b03bc5 100644 --- a/master/fsm_pdo.c +++ b/master/fsm_pdo.c @@ -402,6 +402,11 @@ void ec_fsm_pdo_conf_action_next_sync( 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; diff --git a/master/fsm_slave_config.c b/master/fsm_slave_config.c index 73936246..5bba210b 100644 --- a/master/fsm_slave_config.c +++ b/master/fsm_slave_config.c @@ -58,6 +58,7 @@ void ec_fsm_slave_config_state_fmmu(ec_fsm_slave_config_t *); 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_enter_safeop(ec_fsm_slave_config_t *); 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 @@ void ec_fsm_slave_config_init( 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 @@ void ec_fsm_slave_config_clear( ec_fsm_slave_config_t *fsm /**< slave state machine */ ) { + ec_sdo_request_clear(&fsm->request_copy); } /*****************************************************************************/ @@ -172,6 +178,17 @@ void ec_fsm_slave_config_state_start( 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 @@ void ec_fsm_slave_config_enter_sdo_conf( 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 @@ void ec_fsm_slave_config_state_sdo_conf( 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 @@ void ec_fsm_slave_config_state_pdo_conf( 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 @@ void ec_fsm_slave_config_state_pdo_sync( 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 @@ void ec_fsm_slave_config_state_op( 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 *****************************************************************************/ diff --git a/master/fsm_slave_config.h b/master/fsm_slave_config.h index ddf37876..d03417aa 100644 --- a/master/fsm_slave_config.h +++ b/master/fsm_slave_config.h @@ -66,6 +66,7 @@ struct ec_fsm_slave_config 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. */ }; /*****************************************************************************/ diff --git a/master/sdo_request.c b/master/sdo_request.c index 5b417ec8..e23a7a3c 100644 --- a/master/sdo_request.c +++ b/master/sdo_request.c @@ -83,6 +83,22 @@ void ec_sdo_request_clear( /*****************************************************************************/ +/** 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( diff --git a/master/sdo_request.h b/master/sdo_request.h index ee96ab5a..69ae7367 100644 --- a/master/sdo_request.h +++ b/master/sdo_request.h @@ -75,6 +75,7 @@ struct ec_sdo_request { 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);