Use spinlocks in ec_mini.ko examples

down() must not be used in softirq context:
```
[  613.686994] BUG: sleeping function called from invalid context at ../kernel/locking/semaphore.c:58
[  613.687003] in_atomic(): 0, irqs_disabled(): 0, non_block: 0, pid: 29, name: ktimers/1
[  613.687007] preempt_count: 0, expected: 0
[  613.687009] RCU nest depth: 3, expected: 0
[  613.687013] CPU: 1 PID: 29 Comm: ktimers/1 Tainted: G        W  OE      6.1.38-lp154.12-0601rt #1 1ef8e7f7e45a6388beff51e7b17265074b1375d6
[  613.687020] Hardware name: ICP / iEi IMBA-9454ISA/IMBA-9454ISA(E168), BIOS 080014  02/20/2009
[  613.687023] Call Trace:
[  613.687029]  <TASK>
[  613.687034]  dump_stack_lvl+0x44/0x5c
[  613.687046]  __might_resched+0x171/0x1c0
[  613.687055]  ? check_slave_config_states+0x100/0x100 [ec_mini 7f93b9d1541d0037eab9400e73ee29f252250780]
[  613.687070]  down+0x1e/0x70
[  613.687076]  cyclic_task+0x11/0xdc [ec_mini 7f93b9d1541d0037eab9400e73ee29f252250780]
[  613.687088]  call_timer_fn+0x29/0x190
[  613.687096]  run_timer_softirq+0x4d5/0x570
[  613.687104]  ? __schedule+0x32b/0x1330
[  613.687110]  __do_softirq+0xd5/0x2ec
[  613.687117]  ? smpboot_thread_fn+0x23/0x300
[  613.687127]  run_timersd+0x60/0xb0
[  613.687130]  smpboot_thread_fn+0x24c/0x300
[  613.687133]  ? smpboot_unregister_percpu_thread+0x70/0x70
[  613.687135]  kthread+0x129/0x140
[  613.687138]  ? kthread_complete_and_exit+0x20/0x20
[  613.687141]  ret_from_fork+0x22/0x30
[  613.687146]  </TASK>
```
This commit is contained in:
Bjarne von Horn 2024-02-01 14:02:42 +01:00
parent 2fdea4dd53
commit 7727ac725d
1 changed files with 17 additions and 17 deletions

View File

@ -27,7 +27,7 @@
#include <linux/interrupt.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/semaphore.h>
#include <linux/spinlock.h>
#include "../../include/ecrt.h" // EtherCAT realtime interface
@ -50,7 +50,7 @@
// EtherCAT
static ec_master_t *master = NULL;
static ec_master_state_t master_state = {};
struct semaphore master_sem;
static spinlock_t master_spinlock;
static ec_domain_t *domain1 = NULL;
static ec_domain_state_t domain1_state = {};
@ -188,9 +188,9 @@ void check_domain1_state(void)
{
ec_domain_state_t ds;
down(&master_sem);
spin_lock(&master_spinlock);
ecrt_domain_state(domain1, &ds);
up(&master_sem);
spin_unlock(&master_spinlock);
if (ds.working_counter != domain1_state.working_counter)
printk(KERN_INFO PFX "Domain1: WC %u.\n", ds.working_counter);
@ -206,9 +206,9 @@ void check_master_state(void)
{
ec_master_state_t ms;
down(&master_sem);
spin_lock(&master_spinlock);
ecrt_master_state(master, &ms);
up(&master_sem);
spin_unlock(&master_spinlock);
if (ms.slaves_responding != master_state.slaves_responding)
printk(KERN_INFO PFX "%u slave(s).\n", ms.slaves_responding);
@ -226,9 +226,9 @@ void check_slave_config_states(void)
{
ec_slave_config_state_t s;
down(&master_sem);
spin_lock(&master_spinlock);
ecrt_slave_config_state(sc_ana_in, &s);
up(&master_sem);
spin_unlock(&master_spinlock);
if (s.al_state != sc_ana_in_state.al_state)
printk(KERN_INFO PFX "AnaIn: State 0x%02X.\n", s.al_state);
@ -300,10 +300,10 @@ void cyclic_task(unsigned long data)
#endif
{
// receive process data
down(&master_sem);
spin_lock(&master_spinlock);
ecrt_master_receive(master);
ecrt_domain_process(domain1);
up(&master_sem);
spin_unlock(&master_spinlock);
// check process data state (optional)
check_domain1_state();
@ -336,10 +336,10 @@ void cyclic_task(unsigned long data)
EC_WRITE_U8(domain1_pd + off_dig_out, blink ? 0x06 : 0x09);
// send process data
down(&master_sem);
spin_lock(&master_spinlock);
ecrt_domain_queue(domain1);
ecrt_master_send(master);
up(&master_sem);
spin_unlock(&master_spinlock);
// restart timer
timer.expires += HZ / FREQUENCY;
@ -351,9 +351,9 @@ void cyclic_task(unsigned long data)
void send_callback(void *cb_data)
{
ec_master_t *m = (ec_master_t *) cb_data;
down(&master_sem);
spin_lock_bh(&master_spinlock);
ecrt_master_send_ext(m);
up(&master_sem);
spin_unlock_bh(&master_spinlock);
}
/*****************************************************************************/
@ -361,9 +361,9 @@ void send_callback(void *cb_data)
void receive_callback(void *cb_data)
{
ec_master_t *m = (ec_master_t *) cb_data;
down(&master_sem);
spin_lock_bh(&master_spinlock);
ecrt_master_receive(m);
up(&master_sem);
spin_unlock_bh(&master_spinlock);
}
/*****************************************************************************/
@ -387,7 +387,7 @@ int __init init_mini_module(void)
goto out_return;
}
sema_init(&master_sem, 1);
spin_lock_init(&master_spinlock);
ecrt_master_callbacks(master, send_callback, receive_callback, master);
printk(KERN_INFO PFX "Registering domain...\n");