]> rtime.felk.cvut.cz Git - lincan.git/blobdiff - lincan/include/can_queue.h
Header-files cleanup and CAN queue edges and ends locking reimplemented.
[lincan.git] / lincan / include / can_queue.h
index 15f898a5d06a4bcdf38b1fc86638148708f026ea..5951186166a81f846d9e5f6f6c25b6ce9d39f82c 100644 (file)
@@ -1,30 +1,9 @@
 #ifndef _CAN_QUEUE_H
 #define _CAN_QUEUE_H
 
 #ifndef _CAN_QUEUE_H
 #define _CAN_QUEUE_H
 
-#include <linux/version.h>
-#include <linux/wait.h>
-#include <linux/list.h>
-#include <asm/io.h>
-#include <asm/atomic.h>
 #include "./can.h"
 #include "./constants.h"
 #include "./can.h"
 #include "./constants.h"
-
-/* Next is not sctrictly correct, because of 2.3.0, 2.3.1, 2.3.2
-   kernels need next definitions  too */
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,19)) /* may need correction */
-  #define wait_queue_head_t struct wait_queue *
-  #define wait_queue_t      struct wait_queue
-  #define init_waitqueue_head(queue_head) (*queue_head=NULL)
-  #define init_waitqueue_entry(qentry,qtask) \
-                        (qentry->next=NULL,qentry->task=qtask)
-  #define DECLARE_WAIT_QUEUE_HEAD(name) \
-        struct wait_queue * name=NULL
-  #define DECLARE_WAITQUEUE(wait, current) \
-        struct wait_queue wait = { current, NULL }
-  #define init_MUTEX(sem) (*sem=MUTEX)
-  #define DECLARE_MUTEX(name) struct semaphore name=MUTEX
-#endif /* 2.2.19 */
-
+#include "./can_sysdep.h"
 
 /**
  * struct canque_slot_t - one CAN message slot in the CAN FIFO queue 
 
 /**
  * struct canque_slot_t - one CAN message slot in the CAN FIFO queue 
@@ -83,6 +62,9 @@ struct canque_fifo_t {
 #define CAN_FIFOF_FULL_b       10
 #define CAN_FIFOF_EMPTY_b      9
 #define CAN_FIFOF_DEAD_b       8
 #define CAN_FIFOF_FULL_b       10
 #define CAN_FIFOF_EMPTY_b      9
 #define CAN_FIFOF_DEAD_b       8
+#define CAN_FIFOF_INACTIVE_b   7
+#define CAN_FIFOF_FREEONEMPTY_b        6
+#define CAN_FIFOF_READY_b      5
 
 #define CAN_FIFOF_DESTROY      (1<<CAN_FIFOF_DESTROY_b)
 #define CAN_FIFOF_ERROR                (1<<CAN_FIFOF_ERROR_b)
 
 #define CAN_FIFOF_DESTROY      (1<<CAN_FIFOF_DESTROY_b)
 #define CAN_FIFOF_ERROR                (1<<CAN_FIFOF_ERROR_b)
@@ -92,6 +74,9 @@ struct canque_fifo_t {
 #define CAN_FIFOF_FULL         (1<<CAN_FIFOF_FULL_b)
 #define CAN_FIFOF_EMPTY                (1<<CAN_FIFOF_EMPTY_b)
 #define CAN_FIFOF_DEAD         (1<<CAN_FIFOF_DEAD_b)
 #define CAN_FIFOF_FULL         (1<<CAN_FIFOF_FULL_b)
 #define CAN_FIFOF_EMPTY                (1<<CAN_FIFOF_EMPTY_b)
 #define CAN_FIFOF_DEAD         (1<<CAN_FIFOF_DEAD_b)
+#define CAN_FIFOF_INACTIVE     (1<<CAN_FIFOF_INACTIVE_b)
+#define CAN_FIFOF_FREEONEMPTY  (1<<CAN_FIFOF_FREEONEMPTY_b)
+#define CAN_FIFOF_READY                (1<<CAN_FIFOF_READY_b)
 
 #define canque_fifo_test_fl(fifo,fifo_fl) \
   test_bit(CAN_FIFOF_##fifo_fl##_b,&(fifo)->fifo_flags)
 
 #define canque_fifo_test_fl(fifo,fifo_fl) \
   test_bit(CAN_FIFOF_##fifo_fl##_b,&(fifo)->fifo_flags)
@@ -155,10 +140,11 @@ int canque_fifo_put_inslot(struct canque_fifo_t *fifo, struct canque_slot_t *slo
        if(*fifo->tail) printk(KERN_CRIT "canque_fifo_put_inslot: fifo->tail != NULL\n");
        *fifo->tail=slot;
        fifo->tail=&slot->next;
        if(*fifo->tail) printk(KERN_CRIT "canque_fifo_put_inslot: fifo->tail != NULL\n");
        *fifo->tail=slot;
        fifo->tail=&slot->next;
+       ret=0;
        if(canque_fifo_test_and_clear_fl(fifo,EMPTY))
          ret=CAN_FIFOF_EMPTY;  /* Fifo has been empty before put */
        if(canque_fifo_test_and_clear_fl(fifo,EMPTY))
          ret=CAN_FIFOF_EMPTY;  /* Fifo has been empty before put */
-       else 
-         ret=0;
+       if(canque_fifo_test_and_clear_fl(fifo,INACTIVE))
+         ret=CAN_FIFOF_INACTIVE; /* Fifo has been empty before put */
        spin_unlock_irqrestore(&fifo->fifo_lock, flags);
        return ret;
 }
        spin_unlock_irqrestore(&fifo->fifo_lock, flags);
        return ret;
 }
@@ -312,6 +298,7 @@ struct canque_edge_t {
 
 /**
  * struct canque_ends_t - CAN message delivery subsystem graph vertex (FIFO ends)
 
 /**
  * struct canque_ends_t - CAN message delivery subsystem graph vertex (FIFO ends)
+ * @ends_flags: this field holds flags describing state of the ENDS structure.
  * @active: the array of the lists of active edges directed to the ends structure
  *     with ready messages. The array is indexed by the edges priorities. 
  * @idle: the list of the edges directed to the ends structure with empty FIFOs.
  * @active: the array of the lists of active edges directed to the ends structure
  *     with ready messages. The array is indexed by the edges priorities. 
  * @idle: the list of the edges directed to the ends structure with empty FIFOs.
@@ -337,6 +324,7 @@ struct canque_edge_t {
  * this structure.
  */
 struct canque_ends_t {
  * this structure.
  */
 struct canque_ends_t {
+       unsigned long ends_flags;
        struct list_head active[CANQUEUE_PRIO_NR];
        struct list_head idle;
        struct list_head inlist;
        struct list_head active[CANQUEUE_PRIO_NR];
        struct list_head idle;
        struct list_head inlist;
@@ -355,20 +343,24 @@ struct canque_ends_t {
                        struct chip_t *chip;
                } chipinfo;
        } endinfo;
                        struct chip_t *chip;
                } chipinfo;
        } endinfo;
+       struct list_head dead_peers;
 };
 
 };
 
-#define CANQUEUE_NOTIFY_EMPTY 1        /* out -> in - all slots are processed by FIFO out side */
-#define CANQUEUE_NOTIFY_SPACE 2        /* out -> in - full state negated => there is space for new message */
-#define CANQUEUE_NOTIFY_PROC  3        /* in -> out - empty state negated => out side is requested to process slots */
-#define CANQUEUE_NOTIFY_NOUSR 4        /* called with some lock to prevent edge disappear */
-#define CANQUEUE_NOTIFY_DEAD  5        /*  */
-#define CANQUEUE_NOTIFY_ATACH 6        /*  */
-#define CANQUEUE_NOTIFY_FILTCH 7 /* filter changed */
+#define CANQUEUE_NOTIFY_EMPTY  1 /* out -> in - all slots are processed by FIFO out side */
+#define CANQUEUE_NOTIFY_SPACE  2 /* out -> in - full state negated => there is space for new message */
+#define CANQUEUE_NOTIFY_PROC   3 /* in -> out - empty state negated => out side is requested to process slots */
+#define CANQUEUE_NOTIFY_NOUSR  4 /* called with some lock to prevent edge disappear */
+#define CANQUEUE_NOTIFY_DEAD   5 /*  */
+#define CANQUEUE_NOTIFY_DEAD_WANTED 6 /*  */
+#define CANQUEUE_NOTIFY_ATTACH 7 /*  */
+#define CANQUEUE_NOTIFY_FILTCH 8 /* filter changed */
 #define CANQUEUE_NOTIFY_ERROR      0x10000 /* error notifiers */
 #define CANQUEUE_NOTIFY_ERRTX_PREP 0x11001 /* tx preparation error */
 #define CANQUEUE_NOTIFY_ERRTX_SEND 0x11002 /* tx send error */
 #define CANQUEUE_NOTIFY_ERRTX_BUS  0x11003 /* tx bus error */
 
 #define CANQUEUE_NOTIFY_ERROR      0x10000 /* error notifiers */
 #define CANQUEUE_NOTIFY_ERRTX_PREP 0x11001 /* tx preparation error */
 #define CANQUEUE_NOTIFY_ERRTX_SEND 0x11002 /* tx send error */
 #define CANQUEUE_NOTIFY_ERRTX_BUS  0x11003 /* tx bus error */
 
+#define CAN_ENDSF_DEAD (1<<0)
+
 /**
  * canque_notify_inends - request to send notification to the input ends
  * @qedge: pointer to the edge structure
 /**
  * canque_notify_inends - request to send notification to the input ends
  * @qedge: pointer to the edge structure
@@ -481,6 +473,101 @@ int canque_set_filt(struct canque_edge_t *qedge,
        
 int canque_flush(struct canque_edge_t *qedge);
 
        
 int canque_flush(struct canque_edge_t *qedge);
 
+int canqueue_disconnect_edge(struct canque_edge_t *qedge);
+
+int canqueue_connect_edge(struct canque_edge_t *qedge, struct canque_ends_t *inends, struct canque_ends_t *outends);
+
+int canqueue_ends_init_gen(struct canque_ends_t *qends);
+
+
+/* edge reference and traversal functions */
+
+void canque_edge_do_dead(struct canque_edge_t *edge, int dead_fl);
+
+static inline
+void canque_edge_incref(struct canque_edge_t *edge)
+{
+       atomic_inc(&edge->edge_used);
+}
+
+static inline
+void canque_edge_decref(struct canque_edge_t *edge)
+{
+       unsigned long flags;
+       struct canque_ends_t *inends=edge->inends;
+       struct canque_ends_t *outends=edge->outends;
+       int dead_fl;
+       
+       spin_lock_irqsave(&inends->ends_lock, flags);
+       spin_lock(&outends->ends_lock);
+       if(atomic_dec_and_test(&edge->edge_used)) {
+               dead_fl=canque_fifo_test_and_set_fl(&edge->fifo,DEAD);
+               /*This should not be there, but it cannot be outside of the lock :-(*/
+               canque_notify_bothends(edge,CANQUEUE_NOTIFY_NOUSR);
+               spin_unlock(&outends->ends_lock);
+               spin_unlock_irqrestore(&inends->ends_lock, flags);
+               canque_edge_do_dead(edge, dead_fl);
+       } else {
+               spin_unlock(&outends->ends_lock);
+               spin_unlock_irqrestore(&inends->ends_lock, flags);
+       }
+}
+
+static inline
+struct canque_edge_t *canque_first_inedge(struct canque_ends_t *qends)
+{
+       unsigned long flags;
+       struct list_head *entry;
+       struct canque_edge_t *edge;
+       
+       spin_lock_irqsave(&qends->ends_lock, flags);
+       entry=qends->inlist.next;
+    skip_dead:
+       if(entry != &qends->inlist) {
+               edge=list_entry(entry,struct canque_edge_t,inpeers);
+               if(canque_fifo_test_fl(&edge->fifo,DEAD)) {
+                       entry=entry->next;
+                       goto skip_dead;
+               }
+               canque_edge_incref(edge);
+       } else {
+               edge=NULL;
+       }
+       spin_unlock_irqrestore(&qends->ends_lock, flags);
+       return edge;
+}
+
+
+static inline
+struct canque_edge_t *canque_next_inedge(struct canque_ends_t *qends, struct canque_edge_t *edge)
+{
+       unsigned long flags;
+       struct list_head *entry;
+       struct canque_edge_t *next;
+       
+       spin_lock_irqsave(&qends->ends_lock, flags);
+       entry=edge->inpeers.next;
+    skip_dead:
+       if(entry != &qends->inlist) {
+               next=list_entry(entry,struct canque_edge_t,inpeers);
+               if(canque_fifo_test_fl(&edge->fifo,DEAD)) {
+                       entry=entry->next;
+                       goto skip_dead;
+               }
+               canque_edge_incref(next);
+       } else {
+               next=NULL;
+       }
+       spin_unlock_irqrestore(&qends->ends_lock, flags);
+       canque_edge_decref(edge);
+       return next;
+}
+
+#define canque_for_each_inedge(qends, edge) \
+           for(edge=canque_first_inedge(qends);edge;edge=canque_next_inedge(qends, edge))
+
+/* Linux kernel specific functions */
+
 struct canque_edge_t *canque_new_edge_kern(int slotsnr);
 
 int canque_get_inslot4id_wait_kern(struct canque_ends_t *qends,
 struct canque_edge_t *canque_new_edge_kern(int slotsnr);
 
 int canque_get_inslot4id_wait_kern(struct canque_ends_t *qends,
@@ -492,12 +579,11 @@ int canque_get_outslot_wait_kern(struct canque_ends_t *qends,
 
 int canque_sync_wait_kern(struct canque_ends_t *qends, struct canque_edge_t *qedge);
 
 
 int canque_sync_wait_kern(struct canque_ends_t *qends, struct canque_edge_t *qedge);
 
-int canqueue_connect_edge(struct canque_edge_t *qedge, struct canque_ends_t *inends, struct canque_ends_t *outends);
+int canqueue_ends_init_kern(struct canque_ends_t *qends);
 
 
-int canqueue_ends_init_gen(struct canque_ends_t *qends);
+int canqueue_ends_dispose_kern(struct canque_ends_t *qends, int sync);
 
 
-int canqueue_ends_init_kern(struct canque_ends_t *qends);
+void canqueue_kern_initialize(void);
 
 
-int canqueue_ends_done_kern(struct canque_ends_t *qends, int sync);
 
 #endif /*_CAN_QUEUE_H*/
 
 #endif /*_CAN_QUEUE_H*/