Hi,
I encountered a crash in the ethercat driver when using a bus with a large number of modules (~500). The ec_master_calc_topology_rec() recursive function sometimes exhausts the kernel stack and crashes. I fixed this issue by reimplementing this function in a non-recursive way. As I'm afraid I'm not familiar with mercurial, I will post the code directly here, with two variants: - one for the main repository - one for the gavinl patchset /******* for main repository *************************************************************/ /** Calculates the bus topology. */ typedef struct { ec_slave_t *slave; unsigned int port_index; } topology_stack_t; void ec_master_calc_topology( ec_master_t *master /**< EtherCAT master. */ ) { unsigned int slave_position = 0; ec_slave_t *next_slave; void* stack_base; topology_stack_t* stack_top; static const unsigned int next_table[EC_MAX_PORTS] = { 3, 2, 0, 1 }; if (master->slave_count == 0) return; if (!(stack_base = kmalloc(sizeof(topology_stack_t) * master->slave_count, GFP_KERNEL))) { EC_MASTER_ERR(master, "Failed to allocate stack.\n"); return; } stack_top = (topology_stack_t*)stack_base; // first slave stack_top->slave = master->slaves; stack_top->port_index = 3; ++stack_top; while ( stack_top != (topology_stack_t*)stack_base ) { topology_stack_t* cur = stack_top - 1; if (cur->port_index == 0) { --stack_top; continue; } if (!cur->slave->ports[cur->port_index].link.loop_closed) { slave_position += 1; if (slave_position >= master->slave_count) { kfree(stack_base); EC_MASTER_ERR(master, "Failed to calculate bus topology.\n"); return; } next_slave = master->slaves + slave_position; cur->slave->ports[cur->port_index].next_slave = next_slave; next_slave->ports[0].next_slave = cur->slave; stack_top->slave = next_slave; stack_top->port_index = 3; ++stack_top; } cur->port_index = next_table[cur->port_index]; } kfree(stack_base); } /******* for gavinl patchset *************************************************************/ /** Calculates the bus topology. */ typedef struct { ec_slave_t *slave; unsigned int port_index; } topology_stack_t; void ec_master_calc_topology( ec_master_t *master /**< EtherCAT master. */ ) { unsigned int slave_position = 0; ec_slave_t *next_slave; void* stack_base; topology_stack_t* stack_top; static const unsigned int next_table[EC_MAX_PORTS] = { 3, 2, 0, 1 }; if (master->slave_count == 0) return; if (!(stack_base = kmalloc(sizeof(topology_stack_t) * master->slave_count, GFP_KERNEL))) { EC_MASTER_ERR(master, "Failed to allocate stack.\n"); return; } stack_top = (topology_stack_t*)stack_base; // first slave stack_top->slave = master->slaves; stack_top->port_index = next_table[stack_top->slave->upstream_port]; ++stack_top; while ( stack_top != (topology_stack_t*)stack_base ) { topology_stack_t* cur = stack_top - 1; if (cur->port_index == cur->slave->upstream_port) { --stack_top; continue; } if (!cur->slave->ports[cur->port_index].link.loop_closed) { slave_position += 1; if (slave_position >= master->slave_count) { kfree(stack_base); EC_MASTER_ERR(master, "Failed to calculate bus topology.\n"); return; } next_slave = master->slaves + slave_position; cur->slave->ports[cur->port_index].next_slave = next_slave; next_slave->ports[next_slave->upstream_port].next_slave = cur->slave; stack_top->slave = next_slave; stack_top->port_index = next_table[stack_top->slave->upstream_port]; ++stack_top; } cur->port_index = next_table[cur->port_index]; } kfree(stack_base); } [Disclaimer Solystic]
-- Etherlab-dev mailing list Etherlab-dev@etherlab.org http://lists.etherlab.org/cgi-bin/mailman/listinfo/etherlab-dev