1 /* can_quertl.c - CAN message queues functions for the RT-Linux
2 * Linux CAN-bus device driver.
3 * New CAN queues by Pavel Pisa - OCERA team member
4 * email:pisa@cmp.felk.cvut.cz
5 * This software is released under the GPL-License.
6 * Version lincan-0.2 9 Jul 2003
11 #include "../include/can.h"
12 #include "../include/can_sysdep.h"
13 #include "../include/can_queue.h"
15 #include <rtl_malloc.h>
18 * Modifies Tx message processing
19 * 0 .. local message processing disabled
20 * 1 .. local messages disabled by default but can be enabled by canque_set_filt
21 * 2 .. local messages enabled by default, can be disabled by canque_set_filt
23 extern int processlocal;
26 #define CANQUE_PENDOPS_LIMIT 15
27 #define CANQUE_PENDOPS_MASK ((1<<CANQUE_PENDOPS_LIMIT)-1)
29 struct list_head canque_pending_edges_list;
30 can_spinlock_t canque_pending_edges_lock;
31 unsigned long canqueue_rtl2lin_pend;
33 int canqueue_rtl_irq = 0;
36 canqueue_rtl2lin_handler(int irq, void *ignore, struct pt_regs *ignoreregs)
38 can_spin_irqflags_t flags;
39 struct canque_edge_t *qedge;
40 unsigned pending_inops;
41 unsigned pending_outops;
44 can_spin_lock_irqsave (&canque_pending_edges_lock, flags);
46 while(!list_empty(&canque_pending_edges_list)){
47 qedge=list_entry(canque_pending_edges_list.next,struct canque_edge_t,pending_peers);
48 list_del(&qedge->pending_peers);
49 canque_fifo_clear_fl(&qedge->fifo, NOTIFYPEND);
50 pending_inops=qedge->pending_inops;
51 qedge->pending_inops=0;
52 pending_outops=qedge->pending_outops;
53 qedge->pending_outops=0;
54 can_spin_unlock_irqrestore (&canque_pending_edges_lock, flags);
56 if(pending_outops & ~CANQUE_PENDOPS_MASK){
57 pending_outops &= CANQUE_PENDOPS_MASK;
58 canque_notify_outends(qedge,CANQUEUE_NOTIFY_ERROR | qedge->fifo.error_code);
60 for(i=0;pending_outops;i++,pending_outops>>=1){
62 canque_notify_outends(qedge,i);
64 if(pending_inops & ~CANQUE_PENDOPS_MASK){
65 pending_inops &= CANQUE_PENDOPS_MASK;
66 canque_notify_inends(qedge,CANQUEUE_NOTIFY_ERROR | qedge->fifo.error_code);
68 for(i=0;pending_inops;i++,pending_inops>>=1){
70 canque_notify_inends(qedge,i);
73 canque_edge_decref(qedge);
74 can_spin_lock_irqsave (&canque_pending_edges_lock, flags);
77 can_spin_unlock_irqrestore (&canque_pending_edges_lock, flags);
79 if(test_and_clear_bit(CAN_RTL2LIN_PEND_DEAD_b,&canqueue_rtl2lin_pend))
80 tasklet_schedule(&canque_dead_tl);
87 * canqueue_rtl2lin_check_and_pend - postpones edge notification if called from RT-Linux
88 * @qends: notification target ends
89 * @qedge: edge delivering notification
90 * @what: notification type
92 * Return Value: if called from Linux context, returns 0 and lefts notification processing
93 * on caller responsibility. If called from RT-Linux contexts, schedules postponed
94 * event delivery and returns 1
96 int canqueue_rtl2lin_check_and_pend(struct canque_ends_t *qends,
97 struct canque_edge_t *qedge, int what)
99 can_spin_irqflags_t flags;
101 if(rtl_rt_system_is_idle()) return 0;
103 can_spin_lock_irqsave (&canque_pending_edges_lock, flags);
105 if(what>CANQUE_PENDOPS_LIMIT) what=CANQUE_PENDOPS_LIMIT;
107 if(qends == qedge->inends) {
108 set_bit(what,&qedge->pending_inops);
109 } else if(qends == qedge->outends) {
110 set_bit(what,&qedge->pending_outops);
113 if(!canque_fifo_test_and_set_fl(&qedge->fifo, NOTIFYPEND)){
114 canque_edge_incref(qedge);
115 list_add_tail(&qedge->pending_peers,&canque_pending_edges_list);
116 rtl_global_pend_irq (canqueue_rtl_irq);
119 can_spin_unlock_irqrestore (&canque_pending_edges_lock, flags);
127 * canque_get_inslot4id_wait_rtl - find or wait for best outgoing edge and slot for given ID
128 * @qends: ends structure belonging to calling communication object
129 * @qedgep: place to store pointer to found edge
130 * @slotp: place to store pointer to allocated slot
131 * @cmd: command type for slot
132 * @id: communication ID of message to send into edge
133 * @prio: optional priority of message
135 * Same as canque_get_inslot4id(), except, that it waits for free slot
136 * in case, that queue is full. Function is specific for Linux userspace clients.
137 * Return Value: If there is no usable edge negative value is returned.
139 int canque_get_inslot4id_wait_rtl(struct canque_ends_t *qends,
140 struct canque_edge_t **qedgep, struct canque_slot_t **slotp,
141 int cmd, unsigned long id, int prio)
143 rtl_irqstate_t flags;
148 old_age=atomic_read(&qends->endinfo.rtlinfo.rtl_writeq_age);
149 while((ret=canque_get_inslot4id(qends,qedgep,slotp,cmd,id,prio))==-1){
150 rtl_sigemptyset(&sigset);
151 rtl_spin_lock_irqsave(&qends->endinfo.rtlinfo.rtl_lock, flags);
152 if(old_age == atomic_read(&qends->endinfo.rtlinfo.rtl_writeq_age))
153 sigset=rtl_wait_sleep(&qends->endinfo.rtlinfo.rtl_writeq, &qends->endinfo.rtlinfo.rtl_lock);
154 rtl_spin_unlock_irqrestore(&qends->endinfo.rtlinfo.rtl_lock, flags);
155 if(RTL_SIGINTR(&sigset))
157 old_age=atomic_read(&qends->endinfo.rtlinfo.rtl_writeq_age);
165 * canque_get_outslot_wait_rtl - receive or wait for ready slot for given ends
166 * @qends: ends structure belonging to calling communication object
167 * @qedgep: place to store pointer to found edge
168 * @slotp: place to store pointer to received slot
170 * The same as canque_test_outslot(), except it waits in the case, that there is
171 * no ready slot for given ends. Function is specific for Linux userspace clients.
172 * Return Value: Negative value informs, that there is no ready output
173 * slot for given ends. Positive value is equal to the command
174 * slot has been allocated by the input side.
176 int canque_get_outslot_wait_rtl(struct canque_ends_t *qends,
177 struct canque_edge_t **qedgep, struct canque_slot_t **slotp)
179 rtl_irqstate_t flags;
184 old_age=atomic_read(&qends->endinfo.rtlinfo.rtl_readq_age);
185 while((ret=canque_test_outslot(qends,qedgep,slotp))==-1){
186 rtl_sigemptyset(&sigset);
187 rtl_spin_lock_irqsave(&qends->endinfo.rtlinfo.rtl_lock, flags);
188 if(old_age == atomic_read(&qends->endinfo.rtlinfo.rtl_readq_age))
189 sigset=rtl_wait_sleep(&qends->endinfo.rtlinfo.rtl_readq, &qends->endinfo.rtlinfo.rtl_lock);
190 rtl_spin_unlock_irqrestore(&qends->endinfo.rtlinfo.rtl_lock, flags);
191 if(RTL_SIGINTR(&sigset))
193 old_age=atomic_read(&qends->endinfo.rtlinfo.rtl_readq_age);
200 * canque_sync_wait_rtl - wait for all slots processing
201 * @qends: ends structure belonging to calling communication object
202 * @qedge: pointer to edge
204 * Functions waits for ends transition into empty state.
205 * Return Value: Positive value indicates, that edge empty state has been reached.
206 * Negative or zero value informs about interrupted wait or other problem.
208 int canque_sync_wait_rtl(struct canque_ends_t *qends, struct canque_edge_t *qedge)
210 rtl_irqstate_t flags;
215 old_age=atomic_read(&qends->endinfo.rtlinfo.rtl_emptyq_age);
216 while(!(ret=canque_fifo_test_fl(&qedge->fifo,EMPTY)?1:0)){
217 rtl_sigemptyset(&sigset);
218 rtl_spin_lock_irqsave(&qends->endinfo.rtlinfo.rtl_lock, flags);
219 if(old_age == atomic_read(&qends->endinfo.rtlinfo.rtl_emptyq_age))
220 sigset=rtl_wait_sleep(&qends->endinfo.rtlinfo.rtl_emptyq, &qends->endinfo.rtlinfo.rtl_lock);
221 rtl_spin_unlock_irqrestore(&qends->endinfo.rtlinfo.rtl_lock, flags);
222 if(RTL_SIGINTR(&sigset))
224 old_age=atomic_read(&qends->endinfo.rtlinfo.rtl_emptyq_age);
232 * canque_fifo_init_rtl - initialize one CAN FIFO
233 * @fifo: pointer to the FIFO structure
234 * @slotsnr: number of requested slots
236 * Return Value: The negative value indicates, that there is no memory
237 * to allocate space for the requested number of the slots.
239 int canque_fifo_init_rtl(struct canque_fifo_t *fifo, int slotsnr)
242 if(!slotsnr) slotsnr=MAX_BUF_LENGTH;
243 size=sizeof(struct canque_slot_t)*slotsnr;
244 fifo->entry=rt_malloc(size);
245 if(!fifo->entry) return -1;
246 fifo->slotsnr=slotsnr;
247 return canque_fifo_init_slots(fifo);
252 * canque_fifo_done_rtl - frees slots allocated for CAN FIFO
253 * @fifo: pointer to the FIFO structure
255 int canque_fifo_done_rtl(struct canque_fifo_t *fifo)
258 rt_free(fifo->entry);
263 void canque_dispose_edge_rtl(struct canque_edge_t *qedge)
265 canque_fifo_done_rtl(&qedge->fifo);
270 * canque_new_edge_rtl - allocate new edge structure in the RT-Linux context
271 * @slotsnr: required number of slots in the newly allocated edge structure
273 * Return Value: Returns pointer to allocated slot structure or %NULL if
274 * there is not enough memory to process operation.
276 struct canque_edge_t *canque_new_edge_rtl(int slotsnr)
278 struct canque_edge_t *qedge;
279 qedge = (struct canque_edge_t *)rt_malloc(sizeof(struct canque_edge_t));
280 if(qedge == NULL) return NULL;
282 memset(qedge,0,sizeof(struct canque_edge_t));
283 can_spin_lock_init(&qedge->fifo.fifo_lock);
284 canque_fifo_set_fl(&qedge->fifo,RTL_MEM);
285 if(canque_fifo_init_rtl(&qedge->fifo, slotsnr)<0){
289 atomic_set(&qedge->edge_used,1);
291 qedge->filtmask = canque_filtid2internal(0l, (processlocal<2)? MSG_LOCAL:0);
292 qedge->edge_prio = 0;
293 #if defined(CAN_DEBUG) && 0
294 /* not exactly clean, but enough for debugging */
295 atomic_inc(&edge_num_cnt);
296 qedge->edge_num=atomic_read(&edge_num_cnt);
297 #endif /* CAN_DEBUG */
301 void canque_ends_free_rtl(struct canque_ends_t *qends)
308 * canqueue_notify_rtl - notification callback handler for Linux userspace clients
309 * @qends: pointer to the callback side ends structure
310 * @qedge: edge which invoked notification
311 * @what: notification type
313 void canqueue_notify_rtl(struct canque_ends_t *qends, struct canque_edge_t *qedge, int what)
315 rtl_irqstate_t flags;
318 case CANQUEUE_NOTIFY_EMPTY:
319 rtl_spin_lock_irqsave(&qends->endinfo.rtlinfo.rtl_lock, flags);
320 atomic_inc(&qends->endinfo.rtlinfo.rtl_emptyq_age);
321 rtl_wait_wakeup(&qends->endinfo.rtlinfo.rtl_emptyq);
322 rtl_spin_unlock_irqrestore(&qends->endinfo.rtlinfo.rtl_lock, flags);
323 if(canque_fifo_test_and_clear_fl(&qedge->fifo, FREEONEMPTY))
324 canque_edge_decref(qedge);
326 case CANQUEUE_NOTIFY_SPACE:
327 rtl_spin_lock_irqsave(&qends->endinfo.rtlinfo.rtl_lock, flags);
328 atomic_inc(&qends->endinfo.rtlinfo.rtl_writeq_age);
329 rtl_wait_wakeup(&qends->endinfo.rtlinfo.rtl_writeq);
330 rtl_spin_unlock_irqrestore(&qends->endinfo.rtlinfo.rtl_lock, flags);
332 case CANQUEUE_NOTIFY_PROC:
333 rtl_spin_lock_irqsave(&qends->endinfo.rtlinfo.rtl_lock, flags);
334 atomic_inc(&qends->endinfo.rtlinfo.rtl_readq_age);
335 rtl_wait_wakeup(&qends->endinfo.rtlinfo.rtl_readq);
336 rtl_spin_unlock_irqrestore(&qends->endinfo.rtlinfo.rtl_lock, flags);
338 case CANQUEUE_NOTIFY_NOUSR:
339 rtl_spin_lock_irqsave(&qends->endinfo.rtlinfo.rtl_lock, flags);
341 atomic_inc(&qends->endinfo.rtlinfo.rtl_readq_age);
342 rtl_wait_wakeup(&qends->endinfo.rtlinfo.rtl_readq);
344 atomic_inc(&qends->endinfo.rtlinfo.rtl_writeq_age);
345 rtl_wait_wakeup(&qends->endinfo.rtlinfo.rtl_writeq);
347 atomic_inc(&qends->endinfo.rtlinfo.rtl_emptyq_age);
348 rtl_wait_wakeup(&qends->endinfo.rtlinfo.rtl_emptyq);
350 rtl_spin_unlock_irqrestore(&qends->endinfo.rtlinfo.rtl_lock, flags);
352 case CANQUEUE_NOTIFY_DEAD_WANTED:
353 case CANQUEUE_NOTIFY_DEAD:
354 if(canque_fifo_test_and_clear_fl(&qedge->fifo, READY))
355 canque_edge_decref(qedge);
357 case CANQUEUE_NOTIFY_ATTACH:
364 * canqueue_ends_init_rtl - RT-Linux clients specific ends initialization
365 * @qends: pointer to the callback side ends structure
367 int canqueue_ends_init_rtl(struct canque_ends_t *qends)
369 canqueue_ends_init_gen(qends);
371 rtl_spin_lock_init(&(qends->endinfo.rtlinfo.rtl_lock));
372 rtl_wait_init(&(qends->endinfo.rtlinfo.rtl_readq));
373 rtl_wait_init(&(qends->endinfo.rtlinfo.rtl_writeq));
374 rtl_wait_init(&(qends->endinfo.rtlinfo.rtl_emptyq));
376 qends->notify=canqueue_notify_rtl;
377 qends->endinfo.rtlinfo.pend_flags=0;
382 * canqueue_ends_dispose_rtl - finalizing of the ends structure for Linux kernel clients
383 * @qends: pointer to ends structure
384 * @sync: flag indicating, that user wants to wait for processing of all remaining
387 * Return Value: Function should be designed such way to not fail.
389 int canqueue_ends_dispose_rtl(struct canque_ends_t *qends, int sync)
391 rtl_irqstate_t flags;
394 canqueue_block_inlist(qends);
395 canqueue_block_outlist(qends);
397 /*Wait for sending of all pending messages in the output FIFOs*/
399 canqueue_ends_sync_all_rtl(qends);*/
401 /* Finish or kill all outgoing edges listed in inends */
402 delayed=canqueue_ends_kill_inlist(qends, 1);
403 /* Kill all incoming edges listed in outends */
404 delayed|=canqueue_ends_kill_outlist(qends);
406 rtl_spin_lock_irqsave(&qends->endinfo.rtlinfo.rtl_lock, flags);
407 rtl_wait_wakeup(&qends->endinfo.rtlinfo.rtl_readq);
408 rtl_wait_wakeup(&qends->endinfo.rtlinfo.rtl_writeq);
409 rtl_wait_wakeup(&qends->endinfo.rtlinfo.rtl_emptyq);
410 rtl_spin_unlock_irqrestore(&qends->endinfo.rtlinfo.rtl_lock, flags);
412 if(delayed || !(qends->ends_flags&CAN_ENDSF_MEM_RTL)){
413 canqueue_ends_dispose_postpone(qends);
418 canque_ends_free_rtl(qends);
424 void canqueue_rtl_initialize(void)
426 INIT_LIST_HEAD(&canque_pending_edges_list);
427 can_spin_lock_init(&canque_pending_edges_lock);
429 canqueue_rtl_irq = rtl_get_soft_irq (canqueue_rtl2lin_handler, "rtl_canqueue_irq");
433 void canqueue_rtl_done(void)
435 rtl_free_soft_irq (canqueue_rtl_irq);
440 #endif /*CAN_WITH_RTL*/