#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
* @next: pointer to the next/younger slot
- * @mrs_do_inp: space for flags and optional command describing action
+ * @slot_flags: space for flags and optional command describing action
* associated with slot data
* @msg: space for one CAN message
*
* @head: pointer to the FIFO head, oldest slot
* @tail: pointer to the location, where pointer to newly inserted slot
* should be added
- * @tail: pointer to the location, where pointer to newly inserted slot
+ * @flist: pointer to list of the free slots associated with queue
* @entry: pointer to the memory allocated for the list slots.
* @fifo_lock: the lock to ensure atomicity of slot manipulation operations.
*
#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 chip_t;
/**
- * canque_edge_t - CAN message delivery subsystem graph edge
+ * struct canque_edge_t - CAN message delivery subsystem graph edge
* @fifo: place where primitive @struct canque_fifo_t FIFO is located.
* @filtid: the possible CAN message identifiers filter.
* @filtmask: the filter mask, the comparison considers only
* @edge_used: the atomic usage counter, mainly used for safe destruction of the edge.
* @edge_prio: the assigned queue priority from the range 0 to %CANQUEUE_PRIO_NR-1
* @edge_num: edge sequential number intended for debugging purposes only
+ *
+ * This structure represents one direction connection from messages source
+ * (@inends) to message consumer (@outends) fifo ends hub. The edge contains
+ * &struct canque_fifo_t for message fifo implementation.
*/
struct canque_edge_t {
struct canque_fifo_t fifo;
};
/**
- * canque_edge_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.
* %CANQUEUE_NOTIFY_PROC (in->out call) - empty state negated => out side is requested to process slots.
* %CANQUEUE_NOTIFY_NOUSR (both) - notify, that the last user has released the edge usage
* called with some lock to prevent edge disappear.
+ * %CANQUEUE_NOTIFY_DEAD (both) - edge is in progress of deletion.
+ * %CANQUEUE_NOTIFY_ATACH (both) - new edge has been attached to end.
+ * %CANQUEUE_NOTIFY_FILTCH (out->in call) - edge filter rules changed
+ * %CANQUEUE_NOTIFY_ERROR (out->in call) - error in messages processing.
* @context: space to store ends user specific information
* @endinfo: space to store some other ends usage specific informations
* mainly for waking-up by the notify calls.
+ *
+ * Structure represents place to connect edges to for CAN communication entity.
+ * The zero, one or more incoming and outgoing edges can be connected to
+ * 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
+ * @what: notification type
+ */
static inline
void canque_notify_inends(struct canque_edge_t *qedge, int what)
{
qedge->inends->notify(qedge->inends,qedge,what);
}
+/**
+ * canque_notify_outends - request to send notification to the output ends
+ * @qedge: pointer to the edge structure
+ * @what: notification type
+ */
static inline
void canque_notify_outends(struct canque_edge_t *qedge, int what)
{
qedge->outends->notify(qedge->outends,qedge,what);
}
+/**
+ * canque_notify_bothends - request to send notification to the both ends
+ * @qedge: pointer to the edge structure
+ * @what: notification type
+ */
static inline
void canque_notify_bothends(struct canque_edge_t *qedge, int what)
{
canque_notify_outends(qedge, what);
}
+/**
+ * canque_activate_edge - mark output end of the edge as active
+ * @qedge: pointer to the edge structure
+ * @inends: input side of the edge
+ *
+ * Function call moves output side of the edge from idle onto active edges
+ * list.
+ */
static inline
void canque_activate_edge(struct canque_ends_t *inends, struct canque_edge_t *qedge)
{
spin_unlock_irqrestore(&inends->ends_lock, flags);
}
+/**
+ * canque_filtid2internal - converts message ID and filter flags into internal format
+ * @id: CAN message 11 or 29 bit identifier
+ * @filtflags: CAN message flags
+ *
+ * This function maps message ID and %MSG_RTR, %MSG_EXT and %MSG_LOCAL into one 32 bit number
+ */
+static inline
+unsigned int canque_filtid2internal(unsigned long id, int filtflags)
+{
+ filtflags &= MSG_RTR|MSG_EXT|MSG_LOCAL;
+ filtflags += filtflags&MSG_RTR;
+ return (id&MSG_ID_MASK) | (filtflags<<28);
+}
+
int canque_get_inslot(struct canque_ends_t *qends,
struct canque_edge_t **qedgep, struct canque_slot_t **slotp, int cmd);
struct canque_edge_t *qedge, struct canque_slot_t *slot);
int canque_set_filt(struct canque_edge_t *qedge,
- unsigned long filtid, unsigned long filtmask);
-
+ unsigned long filtid, unsigned long filtmask, int flags);
+
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*/