1 /**************************************************************************/
2 /* File: can_quertl.c - CAN message queues functions for the RT-Linux */
4 /* LinCAN - (Not only) Linux CAN bus driver */
5 /* Copyright (C) 2002-2009 DCE FEE CTU Prague <http://dce.felk.cvut.cz> */
6 /* Copyright (C) 2002-2009 Pavel Pisa <pisa@cmp.felk.cvut.cz> */
7 /* Funded by OCERA and FRESCOR IST projects */
9 /* LinCAN is free software; you can redistribute it and/or modify it */
10 /* under terms of the GNU General Public License as published by the */
11 /* Free Software Foundation; either version 2, or (at your option) any */
12 /* later version. LinCAN is distributed in the hope that it will be */
13 /* useful, but WITHOUT ANY WARRANTY; without even the implied warranty */
14 /* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */
15 /* General Public License for more details. You should have received a */
16 /* copy of the GNU General Public License along with LinCAN; see file */
17 /* COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, */
18 /* Cambridge, MA 02139, USA. */
20 /* To allow use of LinCAN in the compact embedded systems firmware */
21 /* and RT-executives (RTEMS for example), main authors agree with next */
22 /* special exception: */
24 /* Including LinCAN header files in a file, instantiating LinCAN generics */
25 /* or templates, or linking other files with LinCAN objects to produce */
26 /* an application image/executable, does not by itself cause the */
27 /* resulting application image/executable to be covered by */
28 /* the GNU General Public License. */
29 /* This exception does not however invalidate any other reasons */
30 /* why the executable file might be covered by the GNU Public License. */
31 /* Publication of enhanced or derived LinCAN files is required although. */
32 /**************************************************************************/
36 #include "../include/can.h"
37 #include "../include/can_sysdep.h"
38 #include "../include/can_queue.h"
40 #include <rtl_malloc.h>
43 * Modifies Tx message processing
44 * 0 .. local message processing disabled
45 * 1 .. local messages disabled by default but can be enabled by canque_set_filt
46 * 2 .. local messages enabled by default, can be disabled by canque_set_filt
48 extern int processlocal;
51 #define CANQUE_PENDOPS_LIMIT 15
52 #define CANQUE_PENDOPS_MASK ((1<<CANQUE_PENDOPS_LIMIT)-1)
54 struct list_head canque_pending_edges_list;
55 can_spinlock_t canque_pending_edges_lock;
56 unsigned long canqueue_rtl2lin_pend;
58 int canqueue_rtl_irq = 0;
61 canqueue_rtl2lin_handler(int irq, void *ignore, struct pt_regs *ignoreregs)
63 can_spin_irqflags_t flags;
64 struct canque_edge_t *qedge;
65 unsigned pending_inops;
66 unsigned pending_outops;
69 can_spin_lock_irqsave (&canque_pending_edges_lock, flags);
71 while(!list_empty(&canque_pending_edges_list)){
72 qedge=list_entry(canque_pending_edges_list.next,struct canque_edge_t,pending_peers);
73 list_del(&qedge->pending_peers);
74 canque_fifo_clear_fl(&qedge->fifo, NOTIFYPEND);
75 pending_inops=qedge->pending_inops;
76 qedge->pending_inops=0;
77 pending_outops=qedge->pending_outops;
78 qedge->pending_outops=0;
79 can_spin_unlock_irqrestore (&canque_pending_edges_lock, flags);
81 if(pending_outops & ~CANQUE_PENDOPS_MASK){
82 pending_outops &= CANQUE_PENDOPS_MASK;
83 canque_notify_outends(qedge,CANQUEUE_NOTIFY_ERROR | qedge->fifo.error_code);
85 for(i=0;pending_outops;i++,pending_outops>>=1){
87 canque_notify_outends(qedge,i);
89 if(pending_inops & ~CANQUE_PENDOPS_MASK){
90 pending_inops &= CANQUE_PENDOPS_MASK;
91 canque_notify_inends(qedge,CANQUEUE_NOTIFY_ERROR | qedge->fifo.error_code);
93 for(i=0;pending_inops;i++,pending_inops>>=1){
95 canque_notify_inends(qedge,i);
98 canque_edge_decref(qedge);
99 can_spin_lock_irqsave (&canque_pending_edges_lock, flags);
102 can_spin_unlock_irqrestore (&canque_pending_edges_lock, flags);
104 if(test_and_clear_bit(CAN_RTL2LIN_PEND_DEAD_b,&canqueue_rtl2lin_pend))
105 tasklet_schedule(&canque_dead_tl);
112 * canqueue_rtl2lin_check_and_pend - postpones edge notification if called from RT-Linux
113 * @qends: notification target ends
114 * @qedge: edge delivering notification
115 * @what: notification type
117 * Return Value: if called from Linux context, returns 0 and lefts notification processing
118 * on caller responsibility. If called from RT-Linux contexts, schedules postponed
119 * event delivery and returns 1
121 int canqueue_rtl2lin_check_and_pend(struct canque_ends_t *qends,
122 struct canque_edge_t *qedge, int what)
124 can_spin_irqflags_t flags;
126 if(rtl_rt_system_is_idle()) return 0;
128 can_spin_lock_irqsave (&canque_pending_edges_lock, flags);
130 if(what>CANQUE_PENDOPS_LIMIT) what=CANQUE_PENDOPS_LIMIT;
132 if(qends == qedge->inends) {
133 set_bit(what,&qedge->pending_inops);
134 } else if(qends == qedge->outends) {
135 set_bit(what,&qedge->pending_outops);
138 if(!canque_fifo_test_and_set_fl(&qedge->fifo, NOTIFYPEND)){
139 canque_edge_incref(qedge);
140 list_add_tail(&qedge->pending_peers,&canque_pending_edges_list);
141 rtl_global_pend_irq (canqueue_rtl_irq);
144 can_spin_unlock_irqrestore (&canque_pending_edges_lock, flags);
152 * canque_get_inslot4id_wait_rtl - find or wait for best outgoing edge and slot for given ID
153 * @qends: ends structure belonging to calling communication object
154 * @qedgep: place to store pointer to found edge
155 * @slotp: place to store pointer to allocated slot
156 * @cmd: command type for slot
157 * @id: communication ID of message to send into edge
158 * @prio: optional priority of message
160 * Same as canque_get_inslot4id(), except, that it waits for free slot
161 * in case, that queue is full. Function is specific for Linux userspace clients.
162 * Return Value: If there is no usable edge negative value is returned.
164 int canque_get_inslot4id_wait_rtl(struct canque_ends_t *qends,
165 struct canque_edge_t **qedgep, struct canque_slot_t **slotp,
166 int cmd, unsigned long id, int prio)
168 rtl_irqstate_t flags;
173 old_age=atomic_read(&qends->endinfo.rtlinfo.rtl_writeq_age);
174 while((ret=canque_get_inslot4id(qends,qedgep,slotp,cmd,id,prio))==-1){
175 rtl_sigemptyset(&sigset);
176 rtl_spin_lock_irqsave(&qends->endinfo.rtlinfo.rtl_lock, flags);
177 if(old_age == atomic_read(&qends->endinfo.rtlinfo.rtl_writeq_age))
178 sigset=rtl_wait_sleep(&qends->endinfo.rtlinfo.rtl_writeq, &qends->endinfo.rtlinfo.rtl_lock);
179 rtl_spin_unlock_irqrestore(&qends->endinfo.rtlinfo.rtl_lock, flags);
180 if(RTL_SIGINTR(&sigset))
182 old_age=atomic_read(&qends->endinfo.rtlinfo.rtl_writeq_age);
190 * canque_get_outslot_wait_rtl - receive or wait for ready slot for given ends
191 * @qends: ends structure belonging to calling communication object
192 * @qedgep: place to store pointer to found edge
193 * @slotp: place to store pointer to received slot
195 * The same as canque_test_outslot(), except it waits in the case, that there is
196 * no ready slot for given ends. Function is specific for Linux userspace clients.
197 * Return Value: Negative value informs, that there is no ready output
198 * slot for given ends. Positive value is equal to the command
199 * slot has been allocated by the input side.
201 int canque_get_outslot_wait_rtl(struct canque_ends_t *qends,
202 struct canque_edge_t **qedgep, struct canque_slot_t **slotp)
204 rtl_irqstate_t flags;
209 old_age=atomic_read(&qends->endinfo.rtlinfo.rtl_readq_age);
210 while((ret=canque_test_outslot(qends,qedgep,slotp))==-1){
211 rtl_sigemptyset(&sigset);
212 rtl_spin_lock_irqsave(&qends->endinfo.rtlinfo.rtl_lock, flags);
213 if(old_age == atomic_read(&qends->endinfo.rtlinfo.rtl_readq_age))
214 sigset=rtl_wait_sleep(&qends->endinfo.rtlinfo.rtl_readq, &qends->endinfo.rtlinfo.rtl_lock);
215 rtl_spin_unlock_irqrestore(&qends->endinfo.rtlinfo.rtl_lock, flags);
216 if(RTL_SIGINTR(&sigset))
218 old_age=atomic_read(&qends->endinfo.rtlinfo.rtl_readq_age);
225 * canque_sync_wait_rtl - wait for all slots processing
226 * @qends: ends structure belonging to calling communication object
227 * @qedge: pointer to edge
229 * Functions waits for ends transition into empty state.
230 * Return Value: Positive value indicates, that edge empty state has been reached.
231 * Negative or zero value informs about interrupted wait or other problem.
233 int canque_sync_wait_rtl(struct canque_ends_t *qends, struct canque_edge_t *qedge)
235 rtl_irqstate_t flags;
240 old_age=atomic_read(&qends->endinfo.rtlinfo.rtl_emptyq_age);
241 while(!(ret=canque_fifo_test_fl(&qedge->fifo,EMPTY)?1:0)){
242 rtl_sigemptyset(&sigset);
243 rtl_spin_lock_irqsave(&qends->endinfo.rtlinfo.rtl_lock, flags);
244 if(old_age == atomic_read(&qends->endinfo.rtlinfo.rtl_emptyq_age))
245 sigset=rtl_wait_sleep(&qends->endinfo.rtlinfo.rtl_emptyq, &qends->endinfo.rtlinfo.rtl_lock);
246 rtl_spin_unlock_irqrestore(&qends->endinfo.rtlinfo.rtl_lock, flags);
247 if(RTL_SIGINTR(&sigset))
249 old_age=atomic_read(&qends->endinfo.rtlinfo.rtl_emptyq_age);
257 * canque_fifo_init_rtl - initialize one CAN FIFO
258 * @fifo: pointer to the FIFO structure
259 * @slotsnr: number of requested slots
261 * Return Value: The negative value indicates, that there is no memory
262 * to allocate space for the requested number of the slots.
264 int canque_fifo_init_rtl(struct canque_fifo_t *fifo, int slotsnr)
267 if(!slotsnr) slotsnr=MAX_BUF_LENGTH;
268 size=sizeof(struct canque_slot_t)*slotsnr;
269 fifo->entry=rt_malloc(size);
270 if(!fifo->entry) return -1;
271 fifo->slotsnr=slotsnr;
272 return canque_fifo_init_slots(fifo);
277 * canque_fifo_done_rtl - frees slots allocated for CAN FIFO
278 * @fifo: pointer to the FIFO structure
280 int canque_fifo_done_rtl(struct canque_fifo_t *fifo)
283 rt_free(fifo->entry);
288 void canque_dispose_edge_rtl(struct canque_edge_t *qedge)
290 canque_fifo_done_rtl(&qedge->fifo);
295 * canque_new_edge_rtl - allocate new edge structure in the RT-Linux context
296 * @slotsnr: required number of slots in the newly allocated edge structure
298 * Return Value: Returns pointer to allocated slot structure or %NULL if
299 * there is not enough memory to process operation.
301 struct canque_edge_t *canque_new_edge_rtl(int slotsnr)
303 struct canque_edge_t *qedge;
304 qedge = (struct canque_edge_t *)rt_malloc(sizeof(struct canque_edge_t));
305 if(qedge == NULL) return NULL;
307 memset(qedge,0,sizeof(struct canque_edge_t));
308 can_spin_lock_init(&qedge->fifo.fifo_lock);
309 canque_fifo_set_fl(&qedge->fifo,RTL_MEM);
310 if(canque_fifo_init_rtl(&qedge->fifo, slotsnr)<0){
314 atomic_set(&qedge->edge_used,1);
316 qedge->filtmask = canque_filtid2internal(0l, (processlocal<2)? MSG_LOCAL:0);
317 qedge->edge_prio = 0;
318 #if defined(CAN_DEBUG) && 0
319 /* not exactly clean, but enough for debugging */
320 atomic_inc(&edge_num_cnt);
321 qedge->edge_num=atomic_read(&edge_num_cnt);
322 #endif /* CAN_DEBUG */
326 void canque_ends_free_rtl(struct canque_ends_t *qends)
333 * canqueue_notify_rtl - notification callback handler for Linux userspace clients
334 * @qends: pointer to the callback side ends structure
335 * @qedge: edge which invoked notification
336 * @what: notification type
338 void canqueue_notify_rtl(struct canque_ends_t *qends, struct canque_edge_t *qedge, int what)
340 rtl_irqstate_t flags;
343 case CANQUEUE_NOTIFY_EMPTY:
344 rtl_spin_lock_irqsave(&qends->endinfo.rtlinfo.rtl_lock, flags);
345 atomic_inc(&qends->endinfo.rtlinfo.rtl_emptyq_age);
346 rtl_wait_wakeup(&qends->endinfo.rtlinfo.rtl_emptyq);
347 rtl_spin_unlock_irqrestore(&qends->endinfo.rtlinfo.rtl_lock, flags);
348 if(canque_fifo_test_and_clear_fl(&qedge->fifo, FREEONEMPTY))
349 canque_edge_decref(qedge);
351 case CANQUEUE_NOTIFY_SPACE:
352 rtl_spin_lock_irqsave(&qends->endinfo.rtlinfo.rtl_lock, flags);
353 atomic_inc(&qends->endinfo.rtlinfo.rtl_writeq_age);
354 rtl_wait_wakeup(&qends->endinfo.rtlinfo.rtl_writeq);
355 rtl_spin_unlock_irqrestore(&qends->endinfo.rtlinfo.rtl_lock, flags);
357 case CANQUEUE_NOTIFY_PROC:
358 rtl_spin_lock_irqsave(&qends->endinfo.rtlinfo.rtl_lock, flags);
359 atomic_inc(&qends->endinfo.rtlinfo.rtl_readq_age);
360 rtl_wait_wakeup(&qends->endinfo.rtlinfo.rtl_readq);
361 rtl_spin_unlock_irqrestore(&qends->endinfo.rtlinfo.rtl_lock, flags);
363 case CANQUEUE_NOTIFY_NOUSR:
364 rtl_spin_lock_irqsave(&qends->endinfo.rtlinfo.rtl_lock, flags);
366 atomic_inc(&qends->endinfo.rtlinfo.rtl_readq_age);
367 rtl_wait_wakeup(&qends->endinfo.rtlinfo.rtl_readq);
369 atomic_inc(&qends->endinfo.rtlinfo.rtl_writeq_age);
370 rtl_wait_wakeup(&qends->endinfo.rtlinfo.rtl_writeq);
372 atomic_inc(&qends->endinfo.rtlinfo.rtl_emptyq_age);
373 rtl_wait_wakeup(&qends->endinfo.rtlinfo.rtl_emptyq);
375 rtl_spin_unlock_irqrestore(&qends->endinfo.rtlinfo.rtl_lock, flags);
377 case CANQUEUE_NOTIFY_DEAD_WANTED:
378 case CANQUEUE_NOTIFY_DEAD:
379 if(canque_fifo_test_and_clear_fl(&qedge->fifo, READY))
380 canque_edge_decref(qedge);
382 case CANQUEUE_NOTIFY_ATTACH:
389 * canqueue_ends_init_rtl - RT-Linux clients specific ends initialization
390 * @qends: pointer to the callback side ends structure
392 int canqueue_ends_init_rtl(struct canque_ends_t *qends)
394 canqueue_ends_init_gen(qends);
396 rtl_spin_lock_init(&(qends->endinfo.rtlinfo.rtl_lock));
397 rtl_wait_init(&(qends->endinfo.rtlinfo.rtl_readq));
398 rtl_wait_init(&(qends->endinfo.rtlinfo.rtl_writeq));
399 rtl_wait_init(&(qends->endinfo.rtlinfo.rtl_emptyq));
401 qends->notify=canqueue_notify_rtl;
402 qends->endinfo.rtlinfo.pend_flags=0;
407 * canqueue_ends_dispose_rtl - finalizing of the ends structure for Linux kernel clients
408 * @qends: pointer to ends structure
409 * @sync: flag indicating, that user wants to wait for processing of all remaining
412 * Return Value: Function should be designed such way to not fail.
414 int canqueue_ends_dispose_rtl(struct canque_ends_t *qends, int sync)
416 rtl_irqstate_t flags;
419 canqueue_block_inlist(qends);
420 canqueue_block_outlist(qends);
422 /*Wait for sending of all pending messages in the output FIFOs*/
424 canqueue_ends_sync_all_rtl(qends);*/
426 /* Finish or kill all outgoing edges listed in inends */
427 delayed=canqueue_ends_kill_inlist(qends, 1);
428 /* Kill all incoming edges listed in outends */
429 delayed|=canqueue_ends_kill_outlist(qends);
431 rtl_spin_lock_irqsave(&qends->endinfo.rtlinfo.rtl_lock, flags);
432 rtl_wait_wakeup(&qends->endinfo.rtlinfo.rtl_readq);
433 rtl_wait_wakeup(&qends->endinfo.rtlinfo.rtl_writeq);
434 rtl_wait_wakeup(&qends->endinfo.rtlinfo.rtl_emptyq);
435 rtl_spin_unlock_irqrestore(&qends->endinfo.rtlinfo.rtl_lock, flags);
437 if(delayed || !(qends->ends_flags&CAN_ENDSF_MEM_RTL)){
438 canqueue_ends_dispose_postpone(qends);
443 canque_ends_free_rtl(qends);
450 * canqueue_rtl_initialize - initialization of global RT-Linux specific features
452 void canqueue_rtl_initialize(void)
454 INIT_LIST_HEAD(&canque_pending_edges_list);
455 can_spin_lock_init(&canque_pending_edges_lock);
457 canqueue_rtl_irq = rtl_get_soft_irq (canqueue_rtl2lin_handler, "rtl_canqueue_irq");
462 * canqueue_rtl_done - finalization of glopal RT-Linux specific features
464 void canqueue_rtl_done(void)
466 rtl_free_soft_irq (canqueue_rtl_irq);
471 #endif /*CAN_WITH_RTL*/