Fixed serveral races while starting up under high CPU load.
This commit is contained in:
parent
459e7f391c
commit
302c2e77c7
|
|
@ -77,8 +77,11 @@ void ec_datagram_init(ec_datagram_t *datagram /**< EtherCAT datagram */)
|
|||
datagram->index = 0x00;
|
||||
datagram->working_counter = 0x00;
|
||||
datagram->state = EC_DATAGRAM_INIT;
|
||||
datagram->cycles_queued = 0;
|
||||
datagram->cycles_sent = 0;
|
||||
datagram->check_once_more = 0;
|
||||
datagram->jiffies_sent = 0;
|
||||
datagram->cycles_received = 0;
|
||||
datagram->jiffies_received = 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
|
|||
|
|
@ -110,6 +110,7 @@ typedef struct
|
|||
{
|
||||
struct list_head list; /**< needed by domain datagram lists */
|
||||
struct list_head queue; /**< master datagram queue item */
|
||||
struct list_head sent; /**< master list item for sent datagrams */
|
||||
ec_datagram_type_t type; /**< datagram type (APRD, BWR, etc) */
|
||||
ec_address_t address; /**< receipient address */
|
||||
uint8_t *data; /**< datagram data */
|
||||
|
|
@ -118,8 +119,11 @@ typedef struct
|
|||
uint8_t index; /**< datagram index (set by master) */
|
||||
uint16_t working_counter; /**< working counter */
|
||||
ec_datagram_state_t state; /**< datagram state */
|
||||
cycles_t cycles_queued; /**< time, the datagram was queued */
|
||||
cycles_t cycles_sent; /**< time, the datagram was sent */
|
||||
uint8_t check_once_more; /**< one more try in case of timeout */
|
||||
unsigned long jiffies_sent; /**< jiffies when datagram was sent */
|
||||
cycles_t cycles_received; /**< time, the datagram was received */
|
||||
unsigned long jiffies_received; /**< jiffies when datagram was received */
|
||||
}
|
||||
ec_datagram_t;
|
||||
|
||||
|
|
|
|||
|
|
@ -230,6 +230,8 @@ void ec_device_send(ec_device_t *device, /**< EtherCAT device */
|
|||
|
||||
void ec_device_call_isr(ec_device_t *device /**< EtherCAT device */)
|
||||
{
|
||||
device->cycles_isr = get_cycles();
|
||||
device->jiffies_isr = jiffies;
|
||||
if (likely(device->isr)) device->isr(0, device->dev, NULL);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -66,6 +66,8 @@ struct ec_device
|
|||
uint8_t open; /**< true, if the net_device has been opened */
|
||||
struct sk_buff *tx_skb; /**< transmit socket buffer */
|
||||
ec_isr_t isr; /**< pointer to the device's interrupt service routine */
|
||||
cycles_t cycles_isr; /**< cycles of last ISR call */
|
||||
unsigned long jiffies_isr; /**< jiffies of last ISR call */
|
||||
struct module *module; /**< pointer to the device's owning module */
|
||||
uint8_t link_state; /**< device link state */
|
||||
#ifdef EC_DBG_IF
|
||||
|
|
|
|||
54
master/fsm.c
54
master/fsm.c
|
|
@ -1613,8 +1613,8 @@ void ec_fsm_sii_read_check(ec_fsm_t *fsm /**< finite state machine */)
|
|||
return;
|
||||
}
|
||||
|
||||
fsm->sii_start = datagram->cycles_sent;
|
||||
fsm->sii_check_once_more = 1;
|
||||
fsm->sii_start = get_cycles();
|
||||
|
||||
// issue check/fetch datagram
|
||||
if (fsm->sii_mode) {
|
||||
|
|
@ -1649,7 +1649,8 @@ void ec_fsm_sii_read_fetch(ec_fsm_t *fsm /**< finite state machine */)
|
|||
// check "busy bit"
|
||||
if (EC_READ_U8(datagram->data + 1) & 0x81) {
|
||||
// still busy... timeout?
|
||||
if (get_cycles() - fsm->sii_start >= (cycles_t) 10 * cpu_khz) {
|
||||
if (datagram->cycles_received
|
||||
- fsm->sii_start >= (cycles_t) 10 * cpu_khz) {
|
||||
if (!fsm->sii_check_once_more) {
|
||||
EC_ERR("SII: Read timeout.\n");
|
||||
fsm->sii_state = ec_fsm_error;
|
||||
|
|
@ -1727,7 +1728,8 @@ void ec_fsm_sii_write_check(ec_fsm_t *fsm /**< finite state machine */)
|
|||
return;
|
||||
}
|
||||
|
||||
fsm->sii_start = get_cycles();
|
||||
fsm->sii_start = datagram->cycles_sent;
|
||||
fsm->sii_check_once_more = 1;
|
||||
|
||||
// issue check/fetch datagram
|
||||
ec_datagram_nprd(datagram, fsm->slave->station_address, 0x502, 2);
|
||||
|
|
@ -1754,10 +1756,14 @@ void ec_fsm_sii_write_check2(ec_fsm_t *fsm /**< finite state machine */)
|
|||
|
||||
if (EC_READ_U8(datagram->data + 1) & 0x82) {
|
||||
// still busy... timeout?
|
||||
if (get_cycles() - fsm->sii_start >= (cycles_t) 10 * cpu_khz) {
|
||||
EC_ERR("SII: Write timeout.\n");
|
||||
fsm->sii_state = ec_fsm_error;
|
||||
return;
|
||||
if (datagram->cycles_received
|
||||
- fsm->sii_start >= (cycles_t) 10 * cpu_khz) {
|
||||
if (!fsm->sii_check_once_more) {
|
||||
EC_ERR("SII: Write timeout.\n");
|
||||
fsm->sii_state = ec_fsm_error;
|
||||
return;
|
||||
}
|
||||
fsm->sii_check_once_more = 0;
|
||||
}
|
||||
|
||||
// issue check/fetch datagram again
|
||||
|
|
@ -1788,7 +1794,7 @@ void ec_fsm_change_start(ec_fsm_t *fsm /**< finite state machine */)
|
|||
ec_datagram_t *datagram = &fsm->datagram;
|
||||
ec_slave_t *slave = fsm->slave;
|
||||
|
||||
fsm->change_jiffies = jiffies;
|
||||
fsm->change_take_time = 1;
|
||||
|
||||
// write new state to slave
|
||||
ec_datagram_npwr(datagram, slave->station_address, 0x0120, 2);
|
||||
|
|
@ -1815,8 +1821,13 @@ void ec_fsm_change_check(ec_fsm_t *fsm /**< finite state machine */)
|
|||
return;
|
||||
}
|
||||
|
||||
if (fsm->change_take_time) {
|
||||
fsm->change_take_time = 0;
|
||||
fsm->change_jiffies = datagram->jiffies_sent;
|
||||
}
|
||||
|
||||
if (datagram->working_counter != 1) {
|
||||
if (jiffies - fsm->change_jiffies >= 3 * HZ) {
|
||||
if (datagram->jiffies_received - fsm->change_jiffies >= 3 * HZ) {
|
||||
fsm->change_state = ec_fsm_error;
|
||||
EC_ERR("Failed to set state 0x%02X on slave %i: Slave did not"
|
||||
" respond.\n", fsm->change_new, fsm->slave->ring_position);
|
||||
|
|
@ -1830,7 +1841,7 @@ void ec_fsm_change_check(ec_fsm_t *fsm /**< finite state machine */)
|
|||
return;
|
||||
}
|
||||
|
||||
fsm->change_jiffies = jiffies;
|
||||
fsm->change_take_time = 1;
|
||||
|
||||
// read AL status from slave
|
||||
ec_datagram_nprd(datagram, slave->station_address, 0x0130, 2);
|
||||
|
|
@ -1857,6 +1868,11 @@ void ec_fsm_change_status(ec_fsm_t *fsm /**< finite state machine */)
|
|||
return;
|
||||
}
|
||||
|
||||
if (fsm->change_take_time) {
|
||||
fsm->change_take_time = 0;
|
||||
fsm->change_jiffies = datagram->jiffies_sent;
|
||||
}
|
||||
|
||||
slave->current_state = EC_READ_U8(datagram->data);
|
||||
|
||||
if (slave->current_state == fsm->change_new) {
|
||||
|
|
@ -1878,7 +1894,8 @@ void ec_fsm_change_status(ec_fsm_t *fsm /**< finite state machine */)
|
|||
return;
|
||||
}
|
||||
|
||||
if (jiffies - fsm->change_jiffies >= 100 * HZ / 1000) { // 100ms
|
||||
if (datagram->jiffies_received
|
||||
- fsm->change_jiffies >= 100 * HZ / 1000) { // 100ms
|
||||
// timeout while checking
|
||||
fsm->change_state = ec_fsm_error;
|
||||
EC_ERR("Timeout while setting state 0x%02X on slave %i.\n",
|
||||
|
|
@ -1987,7 +2004,7 @@ void ec_fsm_change_ack(ec_fsm_t *fsm /**< finite state machine */)
|
|||
return;
|
||||
}
|
||||
|
||||
fsm->change_jiffies = jiffies;
|
||||
fsm->change_take_time = 1;
|
||||
|
||||
// read new AL status
|
||||
ec_datagram_nprd(datagram, slave->station_address, 0x0130, 2);
|
||||
|
|
@ -2014,6 +2031,11 @@ void ec_fsm_change_check_ack(ec_fsm_t *fsm /**< finite state machine */)
|
|||
return;
|
||||
}
|
||||
|
||||
if (fsm->change_take_time) {
|
||||
fsm->change_take_time = 0;
|
||||
fsm->change_jiffies = datagram->jiffies_sent;
|
||||
}
|
||||
|
||||
ack_state = EC_READ_U8(datagram->data);
|
||||
|
||||
if (ack_state == slave->current_state) {
|
||||
|
|
@ -2023,7 +2045,8 @@ void ec_fsm_change_check_ack(ec_fsm_t *fsm /**< finite state machine */)
|
|||
return;
|
||||
}
|
||||
|
||||
if (jiffies - fsm->change_jiffies >= 100 * HZ / 1000) { // 100ms
|
||||
if (datagram->jiffies_received
|
||||
- fsm->change_jiffies >= 100 * HZ / 1000) { // 100ms
|
||||
// timeout while checking
|
||||
slave->current_state = EC_SLAVE_STATE_UNKNOWN;
|
||||
fsm->change_state = ec_fsm_error;
|
||||
|
|
@ -2097,7 +2120,7 @@ void ec_fsm_coe_down_request(ec_fsm_t *fsm /**< finite state machine */)
|
|||
return;
|
||||
}
|
||||
|
||||
fsm->coe_start = get_cycles();
|
||||
fsm->coe_start = datagram->cycles_sent;
|
||||
|
||||
ec_slave_mbox_prepare_check(slave, datagram); // can not fail.
|
||||
ec_master_queue_datagram(fsm->master, datagram);
|
||||
|
|
@ -2123,7 +2146,8 @@ void ec_fsm_coe_down_check(ec_fsm_t *fsm /**< finite state machine */)
|
|||
}
|
||||
|
||||
if (!ec_slave_mbox_check(datagram)) {
|
||||
if (get_cycles() - fsm->coe_start >= (cycles_t) 100 * cpu_khz) {
|
||||
if (datagram->cycles_received
|
||||
- fsm->coe_start >= (cycles_t) 100 * cpu_khz) {
|
||||
fsm->coe_state = ec_fsm_error;
|
||||
EC_ERR("Timeout while checking SDO configuration on slave %i.\n",
|
||||
slave->ring_position);
|
||||
|
|
|
|||
|
|
@ -72,11 +72,12 @@ struct ec_fsm
|
|||
unsigned int sii_mode; /**< SII reading done by APRD (0) or NPRD (1) */
|
||||
uint8_t sii_value[4]; /**< raw SII value (32bit) */
|
||||
cycles_t sii_start; /**< sii start */
|
||||
uint8_t sii_check_once_more; /**< do one more check in case of timeout */
|
||||
uint8_t sii_check_once_more; /**< one more try after timeout */
|
||||
|
||||
void (*change_state)(ec_fsm_t *); /**< slave state change state function */
|
||||
ec_slave_state_t change_new; /**< input: new state */
|
||||
unsigned long change_jiffies; /**< change timer */
|
||||
uint8_t change_take_time; /**< take sending timestamp */
|
||||
|
||||
void (*coe_state)(ec_fsm_t *); /**< CoE state function */
|
||||
ec_sdo_data_t *sdodata; /**< input/output: SDO data object */
|
||||
|
|
|
|||
|
|
@ -311,6 +311,7 @@ void ec_master_queue_datagram(ec_master_t *master, /**< EtherCAT master */
|
|||
|
||||
list_add_tail(&datagram->queue, &master->datagram_queue);
|
||||
datagram->state = EC_DATAGRAM_QUEUED;
|
||||
datagram->cycles_queued = get_cycles();
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -322,15 +323,18 @@ void ec_master_queue_datagram(ec_master_t *master, /**< EtherCAT master */
|
|||
|
||||
void ec_master_send_datagrams(ec_master_t *master /**< EtherCAT master */)
|
||||
{
|
||||
ec_datagram_t *datagram;
|
||||
ec_datagram_t *datagram, *next;
|
||||
size_t datagram_size;
|
||||
uint8_t *frame_data, *cur_data;
|
||||
void *follows_word;
|
||||
cycles_t cycles_start, cycles_end;
|
||||
cycles_t cycles_start, cycles_sent, cycles_end;
|
||||
unsigned long jiffies_sent;
|
||||
unsigned int frame_count, more_datagrams_waiting;
|
||||
struct list_head sent_datagrams;
|
||||
|
||||
frame_count = 0;
|
||||
cycles_start = get_cycles();
|
||||
frame_count = 0;
|
||||
INIT_LIST_HEAD(&sent_datagrams);
|
||||
|
||||
if (unlikely(master->debug_level > 1))
|
||||
EC_DBG("ec_master_send_datagrams\n");
|
||||
|
|
@ -354,9 +358,7 @@ void ec_master_send_datagrams(ec_master_t *master /**< EtherCAT master */)
|
|||
break;
|
||||
}
|
||||
|
||||
datagram->state = EC_DATAGRAM_SENT;
|
||||
datagram->cycles_sent = cycles_start;
|
||||
datagram->check_once_more = 1;
|
||||
list_add_tail(&datagram->sent, &sent_datagrams);
|
||||
datagram->index = master->datagram_index++;
|
||||
|
||||
if (unlikely(master->debug_level > 1))
|
||||
|
|
@ -384,7 +386,7 @@ void ec_master_send_datagrams(ec_master_t *master /**< EtherCAT master */)
|
|||
cur_data += EC_DATAGRAM_FOOTER_SIZE;
|
||||
}
|
||||
|
||||
if (cur_data - frame_data == EC_FRAME_HEADER_SIZE) {
|
||||
if (list_empty(&sent_datagrams)) {
|
||||
if (unlikely(master->debug_level > 1))
|
||||
EC_DBG("nothing to send.\n");
|
||||
break;
|
||||
|
|
@ -403,6 +405,17 @@ void ec_master_send_datagrams(ec_master_t *master /**< EtherCAT master */)
|
|||
|
||||
// send frame
|
||||
ec_device_send(master->device, cur_data - frame_data);
|
||||
cycles_sent = get_cycles();
|
||||
jiffies_sent = jiffies;
|
||||
|
||||
// set datagram states and sending timestamps
|
||||
list_for_each_entry_safe(datagram, next, &sent_datagrams, sent) {
|
||||
datagram->state = EC_DATAGRAM_SENT;
|
||||
datagram->cycles_sent = cycles_sent;
|
||||
datagram->jiffies_sent = jiffies_sent;
|
||||
list_del_init(&datagram->sent); // empty list of sent datagrams
|
||||
}
|
||||
|
||||
frame_count++;
|
||||
}
|
||||
while (more_datagrams_waiting);
|
||||
|
|
@ -498,6 +511,8 @@ void ec_master_receive_datagrams(ec_master_t *master, /**< EtherCAT master */
|
|||
|
||||
// dequeue the received datagram
|
||||
datagram->state = EC_DATAGRAM_RECEIVED;
|
||||
datagram->cycles_received = master->device->cycles_isr;
|
||||
datagram->jiffies_received = master->device->jiffies_isr;
|
||||
list_del_init(&datagram->queue);
|
||||
}
|
||||
}
|
||||
|
|
@ -1063,8 +1078,7 @@ void ec_master_calc_addressing(ec_master_t *master /**< EtherCAT master */)
|
|||
int ec_master_measure_bus_time(ec_master_t *master)
|
||||
{
|
||||
ec_datagram_t datagram;
|
||||
cycles_t cycles_start, cycles_end, cycles_timeout;
|
||||
uint32_t times[100], sum, min, max, i;
|
||||
uint32_t cur, sum, min, max, i;
|
||||
|
||||
ec_datagram_init(&datagram);
|
||||
|
||||
|
|
@ -1074,7 +1088,7 @@ int ec_master_measure_bus_time(ec_master_t *master)
|
|||
return -1;
|
||||
}
|
||||
|
||||
cycles_timeout = (cycles_t) EC_IO_TIMEOUT * (cpu_khz / 1000);
|
||||
ecrt_master_receive(master);
|
||||
|
||||
sum = 0;
|
||||
min = 0xFFFFFFFF;
|
||||
|
|
@ -1083,11 +1097,9 @@ int ec_master_measure_bus_time(ec_master_t *master)
|
|||
for (i = 0; i < 100; i++) {
|
||||
ec_master_queue_datagram(master, &datagram);
|
||||
ecrt_master_send(master);
|
||||
cycles_start = get_cycles();
|
||||
|
||||
while (1) { // active waiting
|
||||
ec_device_call_isr(master->device);
|
||||
cycles_end = get_cycles(); // take current time
|
||||
while (1) {
|
||||
ecrt_master_receive(master);
|
||||
|
||||
if (datagram.state == EC_DATAGRAM_RECEIVED) {
|
||||
break;
|
||||
|
|
@ -1096,25 +1108,25 @@ int ec_master_measure_bus_time(ec_master_t *master)
|
|||
EC_WARN("Failed to measure bus time.\n");
|
||||
goto error;
|
||||
}
|
||||
else if (cycles_end - cycles_start >= cycles_timeout) {
|
||||
else if (datagram.state == EC_DATAGRAM_TIMED_OUT) {
|
||||
EC_WARN("Timeout while measuring bus time.\n");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
times[i] = (unsigned int) (cycles_end - cycles_start) * 1000 / cpu_khz;
|
||||
sum += times[i];
|
||||
if (times[i] > max) max = times[i];
|
||||
if (times[i] < min) min = times[i];
|
||||
cur = (unsigned int) (datagram.cycles_received
|
||||
- datagram.cycles_sent) * 1000 / cpu_khz;
|
||||
sum += cur;
|
||||
if (cur > max) max = cur;
|
||||
if (cur < min) min = cur;
|
||||
}
|
||||
|
||||
EC_INFO("Bus time is (min/avg/max) %u/%u.%u/%u us.\n",
|
||||
EC_INFO("Bus time is (min/avg/max) %u / %u.%u / %u us.\n",
|
||||
min, sum / 100, sum % 100, max);
|
||||
ec_datagram_clear(&datagram);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
// Dequeue and free datagram
|
||||
list_del(&datagram.queue);
|
||||
ec_datagram_clear(&datagram);
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -1309,24 +1321,28 @@ void ecrt_master_send(ec_master_t *master /**< EtherCAT master */)
|
|||
void ecrt_master_receive(ec_master_t *master /**< EtherCAT master */)
|
||||
{
|
||||
ec_datagram_t *datagram, *next;
|
||||
cycles_t cycles_received, cycles_timeout;
|
||||
cycles_t cycles_timeout;
|
||||
|
||||
// receive datagrams
|
||||
ec_device_call_isr(master->device);
|
||||
|
||||
cycles_received = get_cycles();
|
||||
cycles_timeout = EC_IO_TIMEOUT /* us */ * cpu_khz / 1000;
|
||||
cycles_timeout = (cycles_t) EC_IO_TIMEOUT /* us */ * (cpu_khz / 1000);
|
||||
|
||||
// dequeue all datagrams that timed out
|
||||
list_for_each_entry_safe(datagram, next, &master->datagram_queue, queue) {
|
||||
switch (datagram->state) {
|
||||
case EC_DATAGRAM_SENT:
|
||||
case EC_DATAGRAM_QUEUED:
|
||||
if (cycles_received - datagram->cycles_sent > cycles_timeout) {
|
||||
if (datagram->state == EC_DATAGRAM_SENT
|
||||
&& datagram->check_once_more) {
|
||||
datagram->check_once_more = 0;
|
||||
break;
|
||||
}
|
||||
if (master->device->cycles_isr
|
||||
- datagram->cycles_queued > cycles_timeout) {
|
||||
list_del_init(&datagram->queue);
|
||||
datagram->state = EC_DATAGRAM_TIMED_OUT;
|
||||
master->stats.timeouts++;
|
||||
ec_master_output_stats(master);
|
||||
}
|
||||
break;
|
||||
case EC_DATAGRAM_SENT:
|
||||
if (master->device->cycles_isr
|
||||
- datagram->cycles_sent > cycles_timeout) {
|
||||
list_del_init(&datagram->queue);
|
||||
datagram->state = EC_DATAGRAM_TIMED_OUT;
|
||||
master->stats.timeouts++;
|
||||
|
|
@ -1359,11 +1375,12 @@ void ecrt_master_prepare(ec_master_t *master /**< EtherCAT master */)
|
|||
|
||||
ecrt_master_send(master);
|
||||
|
||||
cycles_start = get_cycles(); // take sending time
|
||||
cycles_timeout = (cycles_t) EC_IO_TIMEOUT * (cpu_khz / 1000);
|
||||
cycles_start = get_cycles();
|
||||
cycles_timeout = (cycles_t) EC_IO_TIMEOUT /* us */ * (cpu_khz / 1000);
|
||||
|
||||
// active waiting
|
||||
while (1) {
|
||||
udelay(100);
|
||||
cycles_end = get_cycles();
|
||||
if (cycles_end - cycles_start >= cycles_timeout) break;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue