diff --git a/master/ioctl.c b/master/ioctl.c index 7526e72d..892e6a36 100644 --- a/master/ioctl.c +++ b/master/ioctl.c @@ -2282,9 +2282,12 @@ static ATTRIBUTES int ec_ioctl_reset( ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ ) { - down(&master->master_sem); - ecrt_master_reset(master); - up(&master->master_sem); +#ifdef EC_IOCTL_RTDM + /* Xenomai/LXRT is like NMI context, so we do a two-stage schedule. */ + irq_work_queue(&master->sc_reset_work_kicker); +#else + schedule_work(&master->sc_reset_work); +#endif return 0; } @@ -4720,6 +4723,13 @@ static long ec_ioctl_both( case EC_IOCTL_MASTER_LINK_STATE: ret = ec_ioctl_master_link_state(master, arg, ctx); break; + case EC_IOCTL_RESET: + if (!ctx->writable) { + ret = -EPERM; + break; + } + ret = ec_ioctl_reset(master, arg, ctx); + break; case EC_IOCTL_REF_CLOCK_TIME: if (!ctx->writable) { ret = -EPERM; @@ -5204,13 +5214,6 @@ static long ec_ioctl_nrt } ret = ec_ioctl_deactivate(master, arg, ctx); break; - case EC_IOCTL_RESET: - if (!ctx->writable) { - ret = -EPERM; - break; - } - ret = ec_ioctl_reset(master, arg, ctx); - break; case EC_IOCTL_SC_SYNC: if (!ctx->writable) { ret = -EPERM; diff --git a/master/master.c b/master/master.c index 8a8c7744..916d5d96 100644 --- a/master/master.c +++ b/master/master.c @@ -107,6 +107,8 @@ static int ec_master_eoe_thread(void *); void ec_master_find_dc_ref_clock(ec_master_t *); void ec_master_clear_device_stats(ec_master_t *); void ec_master_update_device_stats(ec_master_t *); +static void sc_reset_task_kicker(struct irq_work *work); +static void sc_reset_task(struct work_struct *work); /****************************************************************************/ @@ -316,6 +318,9 @@ int ec_master_init(ec_master_t *master, /**< EtherCAT master */ master->dc_ref_config = NULL; master->dc_ref_clock = NULL; + INIT_WORK(&master->sc_reset_work, sc_reset_task); + init_irq_work(&master->sc_reset_work_kicker, sc_reset_task_kicker); + // init character device ret = ec_cdev_init(&master->cdev, master, device_number); if (ret) @@ -383,6 +388,9 @@ void ec_master_clear( ec_cdev_clear(&master->cdev); + irq_work_sync(&master->sc_reset_work_kicker); + cancel_work_sync(&master->sc_reset_work); + #ifdef EC_EOE ec_master_clear_eoe_handlers(master); #endif @@ -3257,6 +3265,27 @@ void ecrt_master_reset(ec_master_t *master) /****************************************************************************/ +static void sc_reset_task_kicker(struct irq_work *work) +{ + struct ec_master *master = + container_of(work, struct ec_master, sc_reset_work_kicker); + schedule_work(&master->sc_reset_work); +} + +/****************************************************************************/ + +static void sc_reset_task(struct work_struct *work) +{ + struct ec_master *master = + container_of(work, struct ec_master, sc_reset_work); + + down(&master->master_sem); + ecrt_master_reset(master); + up(&master->master_sem); +} + +/****************************************************************************/ + /** \cond */ EXPORT_SYMBOL(ecrt_master_create_domain); diff --git a/master/master.h b/master/master.h index 995fc0ca..77bd97be 100644 --- a/master/master.h +++ b/master/master.h @@ -30,11 +30,13 @@ #define __EC_MASTER_H__ #include +#include #include #include #include #include #include +#include #include "device.h" #include "domain.h" @@ -294,6 +296,9 @@ struct ec_master { wait_queue_head_t request_queue; /**< Wait queue for external requests from user space. */ + struct work_struct sc_reset_work; /**< Task to reset slave configuration. */ + struct irq_work sc_reset_work_kicker; /**< NMI-Safe kicker to trigger + reset task above. */ }; /****************************************************************************/