master/master.c
changeset 1489 f77a1182b6f4
parent 1485 5ddc3a455059
child 1500 ed1a733efbc5
--- a/master/master.c	Mon Jun 29 14:27:06 2009 +0000
+++ b/master/master.c	Tue Jun 30 11:11:56 2009 +0000
@@ -75,7 +75,7 @@
 static int ec_master_idle_thread(void *);
 static int ec_master_operation_thread(void *);
 #ifdef EC_EOE
-void ec_master_eoe_run(unsigned long);
+static int ec_master_eoe_thread(void *);
 #endif
 void ec_master_find_dc_ref_clock(ec_master_t *);
 
@@ -158,14 +158,11 @@
     master->thread = NULL;
 
 #ifdef EC_EOE
-    init_timer(&master->eoe_timer);
-    master->eoe_timer.function = ec_master_eoe_run;
-    master->eoe_timer.data = (unsigned long) master;
-    master->eoe_running = 0;
+    master->eoe_thread = NULL;
     INIT_LIST_HEAD(&master->eoe_handlers);
 #endif
 
-    master->internal_lock = SPIN_LOCK_UNLOCKED;
+    init_MUTEX(&master->io_sem);
     master->request_cb = NULL;
     master->release_cb = NULL;
     master->cb_data = NULL;
@@ -380,9 +377,10 @@
 
 /** Internal locking callback.
  */
-int ec_master_request_cb(void *master /**< callback data */)
-{
-    spin_lock(&((ec_master_t *) master)->internal_lock);
+int ec_master_request_cb(void *data /**< callback data */)
+{
+    ec_master_t *master = (ec_master_t *) data;
+    down(&master->io_sem);
     return 0;
 }
 
@@ -390,9 +388,10 @@
 
 /** Internal unlocking callback.
  */
-void ec_master_release_cb(void *master /**< callback data */)
-{
-    spin_unlock(&((ec_master_t *) master)->internal_lock);
+void ec_master_release_cb(void *data /**< callback data */)
+{
+    ec_master_t *master = (ec_master_t *) data;
+    up(&master->io_sem);
 }
 
 /*****************************************************************************/
@@ -953,9 +952,9 @@
         ec_datagram_output_stats(&master->fsm_datagram);
 
         // receive
-        spin_lock_bh(&master->internal_lock);
+        down(&master->io_sem);
         ecrt_master_receive(master);
-        spin_unlock_bh(&master->internal_lock);
+        up(&master->io_sem);
 
         if (master->fsm_datagram.state == EC_DATAGRAM_SENT)
             goto schedule;
@@ -967,10 +966,10 @@
         up(&master->master_sem);
 
         // queue and send
-        spin_lock_bh(&master->internal_lock);
+        down(&master->io_sem);
         ec_master_queue_datagram(master, &master->fsm_datagram);
         ecrt_master_send(master);
-        spin_unlock_bh(&master->internal_lock);
+        up(&master->io_sem);
         
 schedule:
         if (ec_fsm_master_idle(&master->fsm)) {
@@ -1039,7 +1038,9 @@
  */
 void ec_master_eoe_start(ec_master_t *master /**< EtherCAT master */)
 {
-    if (master->eoe_running) {
+    struct sched_param param = { .sched_priority = 0 };
+
+    if (master->eoe_thread) {
         EC_WARN("EoE already running!\n");
         return;
     }
@@ -1052,12 +1053,18 @@
         return;
     }
 
-    EC_INFO("Starting EoE processing.\n");
-    master->eoe_running = 1;
-
-    // start EoE processing
-    master->eoe_timer.expires = jiffies + 10;
-    add_timer(&master->eoe_timer);
+    EC_INFO("Starting EoE thread.\n");
+    master->eoe_thread = kthread_run(ec_master_eoe_thread, master,
+            "EtherCAT-EoE");
+    if (IS_ERR(master->eoe_thread)) {
+        int err = (int) PTR_ERR(master->eoe_thread);
+        EC_ERR("Failed to start EoE thread (error %i)!\n", err);
+        master->eoe_thread = NULL;
+        return;
+    }
+
+    sched_setscheduler(master->eoe_thread, SCHED_NORMAL, &param);
+    set_user_nice(master->eoe_thread, 0);
 }
 
 /*****************************************************************************/
@@ -1066,61 +1073,84 @@
  */
 void ec_master_eoe_stop(ec_master_t *master /**< EtherCAT master */)
 {
-    if (!master->eoe_running) return;
-
-    EC_INFO("Stopping EoE processing.\n");
-
-    del_timer_sync(&master->eoe_timer);
-    master->eoe_running = 0;
+    if (master->eoe_thread) {
+        EC_INFO("Stopping EoE thread.\n");
+
+        kthread_stop(master->eoe_thread);
+        master->eoe_thread = NULL;
+        EC_INFO("EoE thread exited.\n");
+    }
 }
 
 /*****************************************************************************/
 
 /** Does the Ethernet over EtherCAT processing.
  */
-void ec_master_eoe_run(unsigned long data /**< master pointer */)
-{
-    ec_master_t *master = (ec_master_t *) data;
+static int ec_master_eoe_thread(void *priv_data)
+{
+    ec_master_t *master = (ec_master_t *) priv_data;
     ec_eoe_t *eoe;
-    unsigned int none_open = 1;
-    unsigned long restart_jiffies;
-
-    list_for_each_entry(eoe, &master->eoe_handlers, list) {
-        if (ec_eoe_is_open(eoe)) {
-            none_open = 0;
-            break;
-        }
-    }
-    if (none_open)
-        goto queue_timer;
-
-    // receive datagrams
-    if (master->request_cb(master->cb_data))
-        goto queue_timer;
+    unsigned int none_open, sth_to_send, all_idle;
+
+    if (master->debug_level)
+        EC_DBG("EoE thread running.\n");
+
+    while (!kthread_should_stop()) {
+        none_open = 1;
+        all_idle = 1;
+
+        list_for_each_entry(eoe, &master->eoe_handlers, list) {
+            if (ec_eoe_is_open(eoe)) {
+                none_open = 0;
+                break;
+            }
+        }
+        if (none_open)
+            goto schedule;
+
+        // receive datagrams
+        if (master->request_cb(master->cb_data))
+            goto schedule;
+        
+        ecrt_master_receive(master);
+        master->release_cb(master->cb_data);
+
+        // actual EoE processing
+        sth_to_send = 0;
+        list_for_each_entry(eoe, &master->eoe_handlers, list) {
+            ec_eoe_run(eoe);
+            if (eoe->queue_datagram) {
+                sth_to_send = 1;
+            }
+            if (!ec_eoe_is_idle(eoe)) {
+                all_idle = 0;
+            }
+        }
+
+        if (sth_to_send) {
+            // send datagrams
+            if (master->request_cb(master->cb_data)) {
+                goto schedule;
+            }
+            list_for_each_entry(eoe, &master->eoe_handlers, list) {
+                ec_eoe_queue(eoe);
+            }
+            ecrt_master_send(master);
+            master->release_cb(master->cb_data);
+        }
+
+schedule:
+        if (all_idle) {
+            set_current_state(TASK_INTERRUPTIBLE);
+            schedule_timeout(1);
+        } else {
+            schedule();
+        }
+    }
     
-    ecrt_master_receive(master);
-    master->release_cb(master->cb_data);
-
-    // actual EoE processing
-    list_for_each_entry(eoe, &master->eoe_handlers, list) {
-        ec_eoe_run(eoe);
-    }
-
-    // send datagrams
-    if (master->request_cb(master->cb_data)) {
-        goto queue_timer;
-    }
-    list_for_each_entry(eoe, &master->eoe_handlers, list) {
-        ec_eoe_queue(eoe);
-    }
-    ecrt_master_send(master);
-    master->release_cb(master->cb_data);
-
- queue_timer:
-    restart_jiffies = HZ / EC_EOE_FREQUENCY;
-    if (!restart_jiffies) restart_jiffies = 1;
-    master->eoe_timer.expires = jiffies + restart_jiffies;
-    add_timer(&master->eoe_timer);
+    if (master->debug_level)
+        EC_DBG("EoE thread exiting...\n");
+    return 0;
 }
 #endif