#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"
-
-/* 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
#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_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)
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 */
- 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;
}
/**
* 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.
* 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 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 CAN_ENDSF_DEAD (1<<0)
+
/**
* canque_notify_inends - request to send notification to the input ends
* @qedge: pointer to the edge structure
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,
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*/