[Etherlab-dev] Patch for non-recursive ec_master_calc_topology
SOUQUIERES JEROME
jerome.souquieres at solystic.com
Fri Aug 21 15:11:22 CEST 2020
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]
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.etherlab.org/pipermail/etherlab-dev/attachments/20200821/58a97505/attachment.htm>
More information about the Etherlab-dev
mailing list