# HG changeset patch # User Florian Pose # Date 1209125063 0 # Node ID f8b5c6d21705922817be1767e6d738c0be74741a # Parent e82e2e4cdc9b987765d2387b78e856a05725b52a Removed bus validation; slave configuration during realtime operation; improved scan/config busy flags. diff -r e82e2e4cdc9b -r f8b5c6d21705 NEWS --- a/NEWS Thu Apr 24 16:01:19 2008 +0000 +++ b/NEWS Fri Apr 25 12:04:23 2008 +0000 @@ -48,6 +48,7 @@ scheduled for reading and writing during realtime operation. - Exported ecrt_slave_config_sdo(), the generic Sdo configuration function. + - Removed the bus_state and bus_tainted flags from ec_master_state_t. * Mapping of Pdo entries is now supported. * Current Pdo assignment/mapping is now read via CoE during bus scan, using direct Sdo access, independent of the dictionary. @@ -58,6 +59,12 @@ - Added e1000 driver for kernel 2.6.24, thanks to Matthias Luescher. - Added alpha support for the Reaktek r8169 chipset, thanks to Scott Hassan. +* Removed the "bus validation" routines. Slave scanning is now done any time + the bus topology changes, even during realtime operation. Because of this, + the bus_tainted flag was deprecated and removed. +* Slave configuration is not done during ecrt_master_activate() any more, but + later during realtime operation. The state of the configuration can be + queried via the ecrt_domain_state() and ecrt_slave_config_state() functions. * Added support for slaves that do not support the LRW datagram type. Separate domains have to be used for inputs and output. * Allow gaps in PDO mapping read from CoE. diff -r e82e2e4cdc9b -r f8b5c6d21705 TODO --- a/TODO Thu Apr 24 16:01:19 2008 +0000 +++ b/TODO Fri Apr 25 12:04:23 2008 +0000 @@ -8,31 +8,39 @@ Version 1.4.0: -* Remove bus validation; make bus scanning possible at any time. * Remove self_configured flag to avoid unnecessary process data interruptions. * Replace Sysfs interface with cdev and a user space program to replace lsec; move a few sysfs attributes to proc. +* Implement realtime interface via cdev. * Make scanning and configuration run parallel (each). -* Improve slave config allow flag and completion object. * Mailbox state machine using toggle bits. * Mailbox protocol handlers. -* READMEs for examples. * Remove get_cycles() calls and references to cpu_khz to increase portability. * Remove ecdb.h and let lsec output PDO information 'cut-and-pastable' for applications. * SDO write access in sysfs. * Update documentation. -* Do not configure in ecrt_master_activate(), but later in the state machine. * Supply new ec_master_state_t. * Scanning of Sdo dictionary / writing EEPROM in OPERATION state. * Adapt remaining examples. +* READMEs for examples. * Separate Pdo and Pdo entry classes. * Attach Pdo names. * Wait for bus scanning, even when link is not up at ecrt_request_master(). * Implement ecrt_slave_config_state(). * Add something like lsec -n to show numeric vendor IDs. +* Remove the end state of the master state machine. +* Rename the sdodict state to sdo_dictionary. +* Check the position of the acknowledge state. +* Remove the xmldev files. +* Remove some debugging (add_sync_manager, clearing station addresses). +* Rename "Scanning pdo mapping/configuration". +* Separate CoE debugging. +* Make ecrt_master_slave_config() return no error when slave is not present + or invalid. +* Remove ec_master_prepare(). Future issues: diff -r e82e2e4cdc9b -r f8b5c6d21705 documentation/graphs/fsm_master.dot --- a/documentation/graphs/fsm_master.dot Thu Apr 24 16:01:19 2008 +0000 +++ b/documentation/graphs/fsm_master.dot Fri Apr 25 12:04:23 2008 +0000 @@ -11,7 +11,6 @@ action_configure [shape=point,label=""] action_next_slave_state [shape=point,label=""] action_process_states [shape=point,label=""] - action_addresses [shape=point,label=""] start -> broadcast [weight=10] @@ -33,7 +32,6 @@ action_process_states -> end action_next_slave_state -> read_states - action_next_slave_state -> validate_vendor action_next_slave_state -> action_process_states //read_states -> error @@ -43,20 +41,6 @@ //acknowledge -> error acknowledge -> action_next_slave_state - //validate_vendor -> error - validate_vendor -> validate_product - - action_addresses -> end - action_addresses -> rewrite_addresses - - //validate_product -> error - validate_product -> action_addresses - validate_product -> validate_vendor - - //rewrite_addresses -> error - rewrite_addresses -> end - rewrite_addresses -> action_addresses - //clear_addresses -> error clear_addresses -> scan_slaves diff -r e82e2e4cdc9b -r f8b5c6d21705 include/ecrt.h --- a/include/ecrt.h Thu Apr 24 16:01:19 2008 +0000 +++ b/include/ecrt.h Fri Apr 25 12:04:23 2008 +0000 @@ -85,6 +85,7 @@ * - Added an Sdo access interface, working with Sdo requests. These can be * scheduled for reading and writing during realtime operation. * - Exported ecrt_slave_config_sdo(), the generic Sdo configuration function. + * - Removed the bus_state and bus_tainted flags from ec_master_state_t. * * @{ */ @@ -148,28 +149,11 @@ /*****************************************************************************/ -/** Bus state. - * - * This is used in ec_master_state_t. - * - * \deprecated - * \todo remove - */ -typedef enum { - EC_BUS_FAILURE = -1, /**< At least one configured slave is offline. */ - EC_BUS_OK /**< All configured slaves are online. */ -} ec_bus_state_t; - -/*****************************************************************************/ - /** Master state. * * This is used for the output parameter of ecrt_master_state(). */ typedef struct { - ec_bus_state_t bus_state; /**< \see ec_bus_state_t */ - unsigned int bus_tainted; /**< Non-zero, if the bus topology differs from - the requested configuration. */ unsigned int slaves_responding; /**< Number of slaves in the bus. */ } ec_master_state_t; diff -r e82e2e4cdc9b -r f8b5c6d21705 master/fsm_master.c --- a/master/fsm_master.c Thu Apr 24 16:01:19 2008 +0000 +++ b/master/fsm_master.c Fri Apr 25 12:04:23 2008 +0000 @@ -54,9 +54,6 @@ void ec_fsm_master_state_broadcast(ec_fsm_master_t *); void ec_fsm_master_state_read_states(ec_fsm_master_t *); void ec_fsm_master_state_acknowledge(ec_fsm_master_t *); -void ec_fsm_master_state_validate_vendor(ec_fsm_master_t *); -void ec_fsm_master_state_validate_product(ec_fsm_master_t *); -void ec_fsm_master_state_rewrite_addresses(ec_fsm_master_t *); void ec_fsm_master_state_configure_slave(ec_fsm_master_t *); void ec_fsm_master_state_clear_addresses(ec_fsm_master_t *); void ec_fsm_master_state_scan_slaves(ec_fsm_master_t *); @@ -84,8 +81,6 @@ fsm->slaves_responding = 0; fsm->topology_change_pending = 0; fsm->slave_states = EC_SLAVE_STATE_UNKNOWN; - fsm->validate = 0; - fsm->tainted = 0; // init sub-state-machines ec_fsm_slave_config_init(&fsm->fsm_slave_config, fsm->datagram); @@ -212,16 +207,6 @@ EC_INFO("%u slave%s responding.\n", fsm->slaves_responding, fsm->slaves_responding == 1 ? "" : "s"); - - if (master->mode == EC_MASTER_MODE_OPERATION) { - if (fsm->slaves_responding == master->slave_count) { - fsm->validate = 1; // start validation later - } - else { - EC_WARN("Invalid slave count. Bus in tainted state.\n"); - fsm->tainted = 1; - } - } } // slave states changed? @@ -236,15 +221,13 @@ down(&master->scan_sem); if (!master->allow_scan) { up(&master->scan_sem); - } - else { - master->scan_state = EC_REQUEST_BUSY; + } else { + master->scan_busy = 1; up(&master->scan_sem); // topology change when scan is allowed: // clear all slaves and scan the bus fsm->topology_change_pending = 0; - fsm->tainted = 0; fsm->idle = 0; fsm->scan_jiffies = jiffies; @@ -258,7 +241,7 @@ if (!master->slave_count) { // no slaves present -> finish state machine. - master->scan_state = EC_REQUEST_SUCCESS; + master->scan_busy = 0; wake_up_interruptible(&master->scan_queue); fsm->state = ec_fsm_master_state_end; return; @@ -270,7 +253,7 @@ GFP_ATOMIC))) { EC_ERR("Failed to allocate slave %i!\n", i); ec_master_destroy_slaves(master); - master->scan_state = EC_REQUEST_FAILURE; + master->scan_busy = 0; wake_up_interruptible(&master->scan_queue); fsm->state = ec_fsm_master_state_error; return; @@ -279,7 +262,7 @@ if (ec_slave_init(slave, master, i, i + 1)) { // freeing of "slave" already done ec_master_destroy_slaves(master); - master->scan_state = EC_REQUEST_FAILURE; + master->scan_busy = 0; wake_up_interruptible(&master->scan_queue); fsm->state = ec_fsm_master_state_error; return; @@ -504,10 +487,7 @@ return 1; } - if (fsm->config_error) - master->config_state = EC_REQUEST_FAILURE; - else - master->config_state = EC_REQUEST_SUCCESS; + master->config_busy = 0; wake_up_interruptible(&master->config_queue); return 0; } @@ -526,12 +506,12 @@ ec_master_t *master = fsm->master; ec_slave_t *slave; + // Start slave configuration, if it is allowed. down(&master->config_sem); if (!master->allow_config) { up(&master->config_sem); } else { - master->config_state = EC_REQUEST_BUSY; - fsm->config_error = 0; + master->config_busy = 1; up(&master->config_sem); // check for pending slave configurations @@ -603,25 +583,6 @@ } // all slave states read - - // check, if a bus validation has to be done - if (fsm->validate) { - fsm->validate = 0; - list_for_each_entry(slave, &master->slaves, list) { - if (slave->online_state == EC_SLAVE_ONLINE) continue; - - // At least one slave is offline. validate! - EC_INFO("Validating bus.\n"); - fsm->idle = 0; - fsm->slave = list_entry(master->slaves.next, ec_slave_t, list); - fsm->state = ec_fsm_master_state_validate_vendor; - ec_fsm_sii_read(&fsm->fsm_sii, slave, 0x0008, - EC_FSM_SII_USE_INCREMENT_ADDRESS); - ec_fsm_sii_exec(&fsm->fsm_sii); // execute immediately - return; - } - } - ec_fsm_master_action_process_states(fsm); } @@ -699,162 +660,6 @@ /*****************************************************************************/ /** - Master state: VALIDATE_VENDOR. - Validates the vendor ID of a slave. -*/ - -void ec_fsm_master_state_validate_vendor(ec_fsm_master_t *fsm /**< master state machine */) -{ - ec_slave_t *slave = fsm->slave; - - if (ec_fsm_sii_exec(&fsm->fsm_sii)) return; - - if (!ec_fsm_sii_success(&fsm->fsm_sii)) { - fsm->slave->error_flag = 1; - EC_ERR("Failed to validate vendor ID of slave %i.\n", - slave->ring_position); - fsm->state = ec_fsm_master_state_error; - return; - } - - if (EC_READ_U32(fsm->fsm_sii.value) != slave->sii.vendor_id) { - EC_ERR("Slave %i has an invalid vendor ID!\n", slave->ring_position); - fsm->state = ec_fsm_master_state_error; - return; - } - - // vendor ID is ok. check product code. - fsm->state = ec_fsm_master_state_validate_product; - ec_fsm_sii_read(&fsm->fsm_sii, slave, 0x000A, - EC_FSM_SII_USE_INCREMENT_ADDRESS); - ec_fsm_sii_exec(&fsm->fsm_sii); // execute immediately -} - -/*****************************************************************************/ - -/** - Master action: ADDRESS. - Looks for slave, that have lost their configuration and writes - their station address, so that they can be reconfigured later. -*/ - -void ec_fsm_master_action_addresses(ec_fsm_master_t *fsm /**< master state machine */) -{ - ec_datagram_t *datagram = fsm->datagram; - - while (fsm->slave->online_state == EC_SLAVE_ONLINE) { - if (fsm->slave->list.next == &fsm->master->slaves) { // last slave? - fsm->state = ec_fsm_master_state_end; - return; - } - // check next slave - fsm->slave = list_entry(fsm->slave->list.next, ec_slave_t, list); - } - - if (fsm->master->debug_level) - EC_DBG("Reinitializing slave %i.\n", fsm->slave->ring_position); - - // write station address - ec_datagram_apwr(datagram, fsm->slave->ring_position, 0x0010, 2); - EC_WRITE_U16(datagram->data, fsm->slave->station_address); - fsm->retries = EC_FSM_RETRIES; - fsm->state = ec_fsm_master_state_rewrite_addresses; -} - -/*****************************************************************************/ - -/** - Master state: VALIDATE_PRODUCT. - Validates the product ID of a slave. -*/ - -void ec_fsm_master_state_validate_product(ec_fsm_master_t *fsm /**< master state machine */) -{ - ec_slave_t *slave = fsm->slave; - - if (ec_fsm_sii_exec(&fsm->fsm_sii)) return; - - if (!ec_fsm_sii_success(&fsm->fsm_sii)) { - fsm->slave->error_flag = 1; - EC_ERR("Failed to validate product code of slave %i.\n", - slave->ring_position); - fsm->state = ec_fsm_master_state_error; - return; - } - - if (EC_READ_U32(fsm->fsm_sii.value) != slave->sii.product_code) { - EC_ERR("Slave %i: invalid product code!\n", slave->ring_position); - EC_ERR("expected 0x%08X, got 0x%08X.\n", slave->sii.product_code, - EC_READ_U32(fsm->fsm_sii.value)); - fsm->state = ec_fsm_master_state_error; - return; - } - - // have all states been validated? - if (slave->list.next == &fsm->master->slaves) { - fsm->topology_change_pending = 0; - fsm->tainted = 0; - fsm->slave = list_entry(fsm->master->slaves.next, ec_slave_t, list); - // start writing addresses to offline slaves - ec_fsm_master_action_addresses(fsm); - return; - } - - // validate next slave - fsm->slave = list_entry(fsm->slave->list.next, ec_slave_t, list); - fsm->state = ec_fsm_master_state_validate_vendor; - ec_fsm_sii_read(&fsm->fsm_sii, slave, 0x0008, - EC_FSM_SII_USE_INCREMENT_ADDRESS); - ec_fsm_sii_exec(&fsm->fsm_sii); // execute immediately -} - -/*****************************************************************************/ - -/** - Master state: REWRITE ADDRESS. - Checks, if the new station address has been written to the slave. -*/ - -void ec_fsm_master_state_rewrite_addresses(ec_fsm_master_t *fsm - /**< master state machine */ - ) -{ - ec_slave_t *slave = fsm->slave; - ec_datagram_t *datagram = fsm->datagram; - - if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) - return; - - if (datagram->state != EC_DATAGRAM_RECEIVED) { - EC_ERR("Failed to receive address datagram for slave %i" - " (datagram state %i).\n", - slave->ring_position, datagram->state); - fsm->state = ec_fsm_master_state_error; - return; - } - - if (datagram->working_counter != 1) { - EC_ERR("Failed to write station address of slave %i: ", - slave->ring_position); - ec_datagram_print_wc_error(datagram); - fsm->state = ec_fsm_master_state_error; - return; - } - - if (fsm->slave->list.next == &fsm->master->slaves) { // last slave? - fsm->state = ec_fsm_master_state_end; - return; - } - - // check next slave - fsm->slave = list_entry(fsm->slave->list.next, ec_slave_t, list); - // Write new station address to slave - ec_fsm_master_action_addresses(fsm); -} - -/*****************************************************************************/ - -/** * Master state: CLEAR ADDRESSES. */ @@ -871,7 +676,7 @@ if (datagram->state != EC_DATAGRAM_RECEIVED) { EC_ERR("Failed to receive address clearing datagram (state %i).\n", datagram->state); - master->scan_state = EC_REQUEST_FAILURE; + master->scan_busy = 0; wake_up_interruptible(&master->scan_queue); fsm->state = ec_fsm_master_state_error; return; @@ -915,13 +720,11 @@ 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)) { + } else if (ec_eoe_init(eoe, slave)) { EC_ERR("Failed to init EoE handler for slave %u!\n", slave->ring_position); kfree(eoe); - } - else { + } else { list_add_tail(&eoe->list, &master->eoe_handlers); } } @@ -938,6 +741,9 @@ EC_INFO("Bus scanning completed in %u ms.\n", (u32) (jiffies - fsm->scan_jiffies) * 1000 / HZ); + master->scan_busy = 0; + wake_up_interruptible(&master->scan_queue); + // Attach slave configurations ec_master_attach_slave_configs(master); @@ -946,9 +752,6 @@ ec_master_eoe_start(master); #endif - master->scan_state = EC_REQUEST_SUCCESS; - wake_up_interruptible(&master->scan_queue); - fsm->state = ec_fsm_master_state_end; } @@ -966,8 +769,9 @@ if (ec_fsm_slave_config_exec(&fsm->fsm_slave_config)) // execute slave's state machine return; - if (!ec_fsm_slave_config_success(&fsm->fsm_slave_config)) - fsm->config_error = 1; + if (!ec_fsm_slave_config_success(&fsm->fsm_slave_config)) { + // TODO: mark slave_config as failed. + } // configure next slave, if necessary if (ec_fsm_master_action_configure(fsm)) diff -r e82e2e4cdc9b -r f8b5c6d21705 master/fsm_master.h --- a/master/fsm_master.h Thu Apr 24 16:01:19 2008 +0000 +++ b/master/fsm_master.h Fri Apr 25 12:04:23 2008 +0000 @@ -90,10 +90,6 @@ unsigned int slaves_responding; /**< number of responding slaves */ unsigned int topology_change_pending; /**< bus topology changed */ ec_slave_state_t slave_states; /**< states of responding slaves */ - unsigned int validate; /**< non-zero, if validation to do */ - unsigned int tainted; /**< non-zero, if the current bus topology does - not meet the initial conditions */ - unsigned int config_error; /**< error during slave configuration */ ec_slave_t *slave; /**< current slave */ ec_sii_write_request_t *sii_request; /**< SII write request */ off_t sii_index; /**< index to SII write request data */ diff -r e82e2e4cdc9b -r f8b5c6d21705 master/master.c --- a/master/master.c Thu Apr 24 16:01:19 2008 +0000 +++ b/master/master.c Fri Apr 25 12:04:23 2008 +0000 @@ -126,12 +126,12 @@ INIT_LIST_HEAD(&master->configs); - master->scan_state = EC_REQUEST_SUCCESS; + master->scan_busy = 0; master->allow_scan = 1; init_MUTEX(&master->scan_sem); init_waitqueue_head(&master->scan_queue); - master->config_state = EC_REQUEST_SUCCESS; + master->config_busy = 0; master->allow_config = 1; init_MUTEX(&master->config_sem); init_waitqueue_head(&master->config_queue); @@ -146,7 +146,6 @@ master->stats.corrupted = 0; master->stats.unmatched = 0; master->stats.output_jiffies = 0; - master->pdo_slaves_offline = 0; // assume all Pdo slaves online master->frames_timed_out = 0; for (i = 0; i < HZ; i++) { @@ -442,36 +441,38 @@ down(&master->config_sem); master->allow_config = 0; // temporarily disable slave configuration - up(&master->config_sem); - - // wait for slave configuration to complete - if (wait_event_interruptible(master->config_queue, - master->config_state != EC_REQUEST_BUSY)) { - EC_INFO("Finishing slave configuration interrupted by signal.\n"); - goto out_allow; - } - - if (master->debug_level) - EC_DBG("Waiting for pending slave configuration returned.\n"); - - if (master->debug_level) - EC_DBG("Disable scanning, current scan state: %u\n", - master->scan_state); + if (master->config_busy) { + up(&master->config_sem); + + // wait for slave configuration to complete + if (wait_event_interruptible(master->config_queue, + !master->config_busy)) { + EC_INFO("Finishing slave configuration interrupted by signal.\n"); + goto out_allow; + } + + if (master->debug_level) + EC_DBG("Waiting for pending slave configuration returned.\n"); + } else { + up(&master->config_sem); + } + down(&master->scan_sem); master->allow_scan = 0; // 'lock' the slave list - up(&master->scan_sem); - - if (master->scan_state == EC_REQUEST_BUSY) { + if (!master->scan_busy) { + up(&master->scan_sem); + } else { + up(&master->scan_sem); + // wait for slave scan to complete - if (wait_event_interruptible(master->scan_queue, - master->scan_state != EC_REQUEST_BUSY)) { + if (wait_event_interruptible(master->scan_queue, !master->scan_busy)) { EC_INFO("Waiting for slave scan interrupted by signal.\n"); goto out_allow; } - } - - if (master->debug_level) - EC_DBG("Waiting for pending slave scan returned.\n"); + + if (master->debug_level) + EC_DBG("Waiting for pending slave scan returned.\n"); + } // set states for all slaves list_for_each_entry(slave, &master->slaves, list) { @@ -1005,11 +1006,6 @@ off += sprintf(buffer + off, "\nSlaves: %i\n", master->slave_count); - off += sprintf(buffer + off, "Status: %s\n", - master->fsm.tainted ? "TAINTED" : "sane"); - off += sprintf(buffer + off, "Pdo slaves: %s\n", - master->pdo_slaves_offline ? "INCOMPLETE" : "online"); - off += sprintf(buffer + off, "\nDevices:\n"); down(&master->device_sem); @@ -1349,26 +1345,9 @@ domain_offset += domain->data_size; } - // request slave configuration - down(&master->config_sem); master->allow_config = 1; // request the current configuration - up(&master->config_sem); - - if (master->main_device.link_state) { - // wait for configuration to complete - master->config_state = EC_REQUEST_BUSY; - if (wait_event_interruptible(master->config_queue, - master->config_state != EC_REQUEST_BUSY)) { - EC_INFO("Waiting for configuration interrupted by signal.\n"); - return -1; - } - - if (master->config_state != EC_REQUEST_SUCCESS) { - EC_ERR("Failed to configure slaves.\n"); - return -1; - } - } - + master->allow_scan = 1; // allow re-scanning on topology change + // restart EoE process and master thread with new locking #ifdef EC_EOE ec_master_eoe_stop(master); @@ -1390,6 +1369,7 @@ EC_ERR("Failed to start master thread!\n"); return -1; } + #ifdef EC_EOE ec_master_eoe_start(master); #endif @@ -1532,10 +1512,6 @@ void ecrt_master_state(const ec_master_t *master, ec_master_state_t *state) { - state->bus_state = - (master->pdo_slaves_offline || master->frames_timed_out) - ? EC_BUS_FAILURE : EC_BUS_OK; - state->bus_tainted = master->fsm.tainted; state->slaves_responding = master->fsm.slaves_responding; } diff -r e82e2e4cdc9b -r f8b5c6d21705 master/master.h --- a/master/master.h Thu Apr 24 16:01:19 2008 +0000 +++ b/master/master.h Fri Apr 25 12:04:23 2008 +0000 @@ -104,14 +104,14 @@ struct list_head configs; /**< Bus configuration list. */ unsigned int configs_attached; /**< Slave configurations were attached. */ - ec_request_state_t scan_state; /**< current scanning state */ + unsigned int scan_busy; /**< Current scan state. */ unsigned int allow_scan; /**< non-zero, if slave scanning is allowed */ struct semaphore scan_sem; /**< semaphore protecting the scan_state variable and the allow_scan flag */ wait_queue_head_t scan_queue; /**< queue for processes that wait for slave scanning */ - ec_request_state_t config_state; /**< state of slave configuration */ + unsigned int config_busy; /**< State of slave configuration. */ unsigned int allow_config; /**< non-zero, if slave scanning is allowed */ struct semaphore config_sem; /**< semaphore protecting the config_state variable and the allow_config flag */ @@ -125,9 +125,6 @@ int debug_level; /**< master debug level */ ec_stats_t stats; /**< cyclic statistics */ - unsigned int pdo_slaves_offline; /**< number of slaves, for which Pdos - were registered and that are offline - (used for bus status) */ unsigned int frames_timed_out; /**< there were frame timeouts in the last call to ecrt_master_receive() */