]> rtime.felk.cvut.cz Git - lincan.git/blob - lincan/src/can_queue.c
Intel 82527 chip now configures acceptance identifiers and mask 15 according to edges.
[lincan.git] / lincan / src / can_queue.c
1 /* can_queue.c - CAN message queues
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
7  */
8
9 #include "../include/can.h"
10 #include "../include/can_sysdep.h"
11 #include "../include/can_queue.h"
12
13 /* 
14  * Modifies Tx message processing 
15  *  0 .. local message processing disabled
16  *  1 .. local messages disabled by default but can be enabled by canque_set_filt
17  *  2 .. local messages enabled by default, can be disabled by canque_set_filt
18  */
19 extern int processlocal;
20
21 atomic_t edge_num_cnt;
22
23 //#define CAN_DEBUG
24 #undef CAN_DEBUG
25
26 #ifdef CAN_DEBUG
27         #define DEBUGQUE(fmt,args...) can_printk(KERN_ERR "can_queue (debug): " fmt,\
28         ##args)
29
30 #else
31         #define DEBUGQUE(fmt,args...)
32 #endif
33
34 #define CANQUE_ROUNDROB 1
35
36
37 /**
38  * canque_fifo_flush_slots - free all ready slots from the FIFO
39  * @fifo: pointer to the FIFO structure
40  *
41  * The caller should be prepared to handle situations, when some
42  * slots are held by input or output side slots processing.
43  * These slots cannot be flushed or their processing interrupted.
44  *
45  * Return Value: The nonzero value indicates, that queue has not been
46  *      empty before the function call.
47  */
48 int canque_fifo_flush_slots(struct canque_fifo_t *fifo)
49 {
50         int ret;
51         can_spin_irqflags_t flags;
52         struct canque_slot_t *slot;
53         can_spin_lock_irqsave(&fifo->fifo_lock, flags);
54         slot=fifo->head;
55         if(slot){
56                 *fifo->tail=fifo->flist;
57                 fifo->flist=slot;
58                 fifo->head=NULL;
59                 fifo->tail=&fifo->head;
60         }
61         canque_fifo_clear_fl(fifo,FULL);
62         ret=canque_fifo_test_and_set_fl(fifo,EMPTY)?0:1;
63         can_spin_unlock_irqrestore(&fifo->fifo_lock, flags);
64         return ret;
65 }
66
67
68 /**
69  * canque_fifo_init_slots - initializes slot chain of one CAN FIFO
70  * @fifo: pointer to the FIFO structure
71  *
72  * Return Value: The negative value indicates, that there is no memory
73  *      to allocate space for the requested number of the slots.
74  */
75 int canque_fifo_init_slots(struct canque_fifo_t *fifo)
76 {
77         struct canque_slot_t *slot;
78         int slotsnr=fifo->slotsnr;
79         if(!fifo->entry || !slotsnr) return -1;
80         slot=fifo->entry;
81         fifo->flist=slot;
82         while(--slotsnr){
83                 slot->next=slot+1;
84                 slot++;
85         }
86         slot->next=NULL;
87         fifo->head=NULL;
88         fifo->tail=&fifo->head;
89         canque_fifo_set_fl(fifo,EMPTY);
90         return 1;
91 }
92
93 /* atomic_dec_and_test(&qedge->edge_used);
94  void atomic_inc(&qedge->edge_used);
95  list_add_tail(struct list_head *new, struct list_head *head)
96  list_for_each(edge,qends->inlist);
97  list_entry(ptr, type, member)
98 */
99
100 /**
101  * canque_get_inslot - finds one outgoing edge and allocates slot from it
102  * @qends: ends structure belonging to calling communication object
103  * @qedgep: place to store pointer to found edge
104  * @slotp: place to store pointer to  allocated slot
105  * @cmd: command type for slot
106  *
107  * Function looks for the first non-blocked outgoing edge in @qends structure
108  * and tries to allocate slot from it.
109  * Return Value: If there is no usable edge or there is no free slot in edge
110  *      negative value is returned.
111  */
112 int canque_get_inslot(struct canque_ends_t *qends,
113         struct canque_edge_t **qedgep, struct canque_slot_t **slotp, int cmd)
114 {
115         int ret=-2;
116         struct canque_edge_t *edge;
117         
118         edge=canque_first_inedge(qends);
119         if(edge){
120                 if(!canque_fifo_test_fl(&edge->fifo,BLOCK)){
121                         ret=canque_fifo_get_inslot(&edge->fifo, slotp, cmd);
122                         if(ret>0){
123                                 *qedgep=edge;
124                                 DEBUGQUE("canque_get_inslot cmd=%d found edge %d\n",cmd,edge->edge_num);
125                                 return ret;
126
127                         }
128                 }
129                 canque_edge_decref(edge);
130         }
131         *qedgep=NULL;
132         DEBUGQUE("canque_get_inslot cmd=%d failed\n",cmd);
133         return ret;
134 }
135
136 /**
137  * canque_get_inslot4id - finds best outgoing edge and slot for given ID
138  * @qends: ends structure belonging to calling communication object
139  * @qedgep: place to store pointer to found edge
140  * @slotp: place to store pointer to  allocated slot
141  * @cmd: command type for slot
142  * @id: communication ID of message to send into edge
143  * @prio: optional priority of message
144  *
145  * Function looks for the non-blocked outgoing edge accepting messages
146  * with given ID. If edge is found, slot is allocated from that edge.
147  * The edges with non-zero mask are preferred over edges open to all messages.
148  * If more edges with mask accepts given message ID, the edge with
149  * highest priority below or equal to required priority is selected.
150  * Return Value: If there is no usable edge or there is no free slot in edge
151  *      negative value is returned.
152  */
153 int canque_get_inslot4id(struct canque_ends_t *qends,
154         struct canque_edge_t **qedgep, struct canque_slot_t **slotp,
155         int cmd, unsigned long id, int prio)
156 {
157         int ret=-2;
158         struct canque_edge_t *edge, *bestedge=NULL;
159         
160         canque_for_each_inedge(qends, edge){
161                 if(canque_fifo_test_fl(&edge->fifo,BLOCK))
162                         continue;
163                 if((id^edge->filtid)&edge->filtmask)
164                         continue;
165                 if(bestedge){
166                         if(bestedge->filtmask){
167                                 if (!edge->filtmask) continue;
168                         } else {
169                                 if(edge->filtmask){
170                                         canque_edge_decref(bestedge);
171                                         bestedge=edge;
172                                         canque_edge_incref(bestedge);
173                                         continue;
174                                 }
175                         }
176                         if(bestedge->edge_prio<edge->edge_prio){
177                                 if(edge->edge_prio>prio) continue;
178                         } else {
179                                 if(bestedge->edge_prio<=prio) continue;
180                         }
181                         canque_edge_decref(bestedge);
182                 }
183                 bestedge=edge;
184                 canque_edge_incref(bestedge);
185         }
186         if((edge=bestedge)!=NULL){
187                 ret=canque_fifo_get_inslot(&edge->fifo, slotp, cmd);
188                 if(ret>0){
189                         *qedgep=edge;
190                         DEBUGQUE("canque_get_inslot4id cmd=%d id=%ld prio=%d found edge %d\n",cmd,id,prio,edge->edge_num);
191                         return ret;
192                 }
193                 canque_edge_decref(bestedge);
194         }
195         *qedgep=NULL;
196         DEBUGQUE("canque_get_inslot4id cmd=%d id=%ld prio=%d failed\n",cmd,id,prio);
197         return ret;
198 }
199
200
201 /**
202  * canque_put_inslot - schedules filled slot for processing
203  * @qends: ends structure belonging to calling communication object
204  * @qedge: edge slot belong to
205  * @slot: pointer to the prepared slot
206  *
207  * Puts slot previously acquired by canque_get_inslot() or canque_get_inslot4id()
208  * function call into FIFO queue and activates edge processing if needed.
209  * Return Value: Positive value informs, that activation of output end
210  *      has been necessary
211  */
212 int canque_put_inslot(struct canque_ends_t *qends,
213         struct canque_edge_t *qedge, struct canque_slot_t *slot)
214 {
215         int ret;
216         ret=canque_fifo_put_inslot(&qedge->fifo,slot);
217         if(ret) {
218                 canque_activate_edge(qends,qedge);
219                 canque_notify_outends(qedge,CANQUEUE_NOTIFY_PROC);
220         }
221         canque_edge_decref(qedge);
222         DEBUGQUE("canque_put_inslot for edge %d returned %d\n",qedge->edge_num,ret);
223         return ret;
224 }
225
226 /**
227  * canque_abort_inslot - aborts preparation of the message in the slot
228  * @qends: ends structure belonging to calling communication object
229  * @qedge: edge slot belong to
230  * @slot: pointer to the previously allocated slot
231  *
232  * Frees slot previously acquired by canque_get_inslot() or canque_get_inslot4id()
233  * function call. Used when message copying into slot fails.
234  * Return Value: Positive value informs, that queue full state has been negated.
235  */
236 int canque_abort_inslot(struct canque_ends_t *qends,
237         struct canque_edge_t *qedge, struct canque_slot_t *slot)
238 {
239         int ret;
240         ret=canque_fifo_abort_inslot(&qedge->fifo,slot);
241         if(ret) {
242                 canque_notify_outends(qedge,CANQUEUE_NOTIFY_SPACE);
243         }
244         canque_edge_decref(qedge);
245         DEBUGQUE("canque_abort_inslot for edge %d returned %d\n",qedge->edge_num,ret);
246         return ret;
247 }
248
249 /**
250  * canque_filter_msg2edges - sends message into all edges which accept its ID
251  * @qends: ends structure belonging to calling communication object
252  * @msg: pointer to CAN message
253  *
254  * Sends message to all outgoing edges connected to the given ends, which accepts
255  * message communication ID.
256  * Return Value: Returns number of edges message has been send to
257  */
258 int canque_filter_msg2edges(struct canque_ends_t *qends, struct canmsg_t *msg)
259 {
260         int destnr=0;
261         int ret;
262         unsigned long msgid;
263         struct canque_edge_t *edge;
264         struct canque_slot_t *slot;
265         
266         DEBUGQUE("canque_filter_msg2edges for msg ID 0x%08lx and flags 0x%02x\n",
267                         msg->id, msg->flags);
268         msgid = canque_filtid2internal(msg->id, msg->flags);
269
270         canque_for_each_inedge(qends, edge) {
271                 if(canque_fifo_test_fl(&edge->fifo,BLOCK))
272                         continue;
273                 if((msgid^edge->filtid)&edge->filtmask)
274                         continue;
275                 ret=canque_fifo_get_inslot(&edge->fifo, &slot, 0);
276                 if(ret>0){
277                         slot->msg=*msg;
278                         destnr++;
279                         ret=canque_fifo_put_inslot(&edge->fifo,slot);
280                         if(ret) {
281                                 canque_activate_edge(qends,edge);
282                                 canque_notify_outends(edge,CANQUEUE_NOTIFY_PROC);
283                         }
284
285                 }
286         }
287         DEBUGQUE("canque_filter_msg2edges sent msg ID %ld to %d edges\n",msg->id,destnr);
288         return destnr;
289 }
290
291 /**
292  * canque_test_outslot - test and retrieve ready slot for given ends
293  * @qends: ends structure belonging to calling communication object
294  * @qedgep: place to store pointer to found edge
295  * @slotp: place to store pointer to received slot
296  *
297  * Function takes highest priority active incoming edge and retrieves
298  * oldest ready slot from it.
299  * Return Value: Negative value informs, that there is no ready output
300  *      slot for given ends. Positive value is equal to the command
301  *      slot has been allocated by the input side.
302  */
303 int canque_test_outslot(struct canque_ends_t *qends,
304         struct canque_edge_t **qedgep, struct canque_slot_t **slotp)
305 {
306         can_spin_irqflags_t flags;
307         int prio;
308         struct canque_edge_t *edge;
309         int ret;
310         
311         can_spin_lock_irqsave(&qends->ends_lock, flags);
312         for(prio=CANQUEUE_PRIO_NR;--prio>=0;){
313                 while(!list_empty(&qends->active[prio])){
314                         edge=list_entry(qends->active[prio].next,struct canque_edge_t,activepeers);
315                         if(!canque_fifo_test_fl(&edge->fifo,DEAD)) {
316                                 canque_edge_incref(edge);
317                                 can_spin_unlock_irqrestore(&qends->ends_lock, flags);
318                                 *qedgep=edge;
319                                 DEBUGQUE("canque_test_outslot found edge %d\n",edge->edge_num);
320                                 ret=canque_fifo_test_outslot(&edge->fifo, slotp);
321                                 if(ret>=0)
322                                         return ret;
323                                 can_spin_lock_irqsave(&qends->ends_lock, flags);
324                         }
325                         can_spin_lock(&edge->fifo.fifo_lock);
326                         if(canque_fifo_test_and_set_fl(&edge->fifo,INACTIVE)) {
327                                 list_del(&edge->activepeers);
328                                 list_add(&edge->activepeers,&qends->idle);
329                         }
330                         can_spin_unlock(&edge->fifo.fifo_lock);
331                 }
332         }
333         can_spin_unlock_irqrestore(&qends->ends_lock, flags);
334         *qedgep=NULL;
335         DEBUGQUE("canque_test_outslot no ready slot\n");
336         return -1;
337 }
338
339 /**
340  * canque_free_outslot - frees processed output slot
341  * @qends: ends structure belonging to calling communication object
342  * @qedge: edge slot belong to
343  * @slot: pointer to the processed slot
344  *
345  * Function releases processed slot previously acquired by canque_test_outslot()
346  * function call.
347  * Return Value: Return value informs if input side has been notified
348  *      to know about change of edge state
349  */
350 int canque_free_outslot(struct canque_ends_t *qends,
351         struct canque_edge_t *qedge, struct canque_slot_t *slot)
352 {
353         int ret;
354         can_spin_irqflags_t flags;
355         ret=canque_fifo_free_outslot(&qedge->fifo, slot);
356         if(ret&CAN_FIFOF_EMPTY){
357                 canque_notify_inends(qedge,CANQUEUE_NOTIFY_EMPTY);
358         }
359         if(ret&CAN_FIFOF_FULL)
360                 canque_notify_inends(qedge,CANQUEUE_NOTIFY_SPACE);
361         can_spin_lock_irqsave(&qends->ends_lock, flags);
362         if((ret&CAN_FIFOF_EMPTY) || CANQUE_ROUNDROB ){
363                 can_spin_lock(&qedge->fifo.fifo_lock);
364                 if(canque_fifo_test_fl(&qedge->fifo,EMPTY)){
365                         canque_fifo_set_fl(&qedge->fifo,INACTIVE);
366                         list_del(&qedge->activepeers);
367                         list_add(&qedge->activepeers,&qends->idle);
368                 } else{
369                         list_del(&qedge->activepeers);
370                         list_add_tail(&qedge->activepeers,&qends->active[qedge->edge_prio]);
371                 }
372                 can_spin_unlock(&qedge->fifo.fifo_lock);
373         }
374         can_spin_unlock_irqrestore(&qends->ends_lock, flags);
375         canque_edge_decref(qedge);
376         DEBUGQUE("canque_free_outslot for edge %d returned %d\n",qedge->edge_num,ret);
377         return ret;
378 }
379
380 /**
381  * canque_again_outslot - reschedule output slot to process it again later
382  * @qends: ends structure belonging to calling communication object
383  * @qedge: edge slot belong to
384  * @slot: pointer to the slot for re-processing
385  *
386  * Function reschedules slot previously acquired by canque_test_outslot()
387  * function call for second time processing.
388  * Return Value: Function cannot fail.
389  */
390 int canque_again_outslot(struct canque_ends_t *qends,
391         struct canque_edge_t *qedge, struct canque_slot_t *slot)
392 {
393         int ret;
394         ret=canque_fifo_again_outslot(&qedge->fifo, slot);
395         canque_edge_decref(qedge);
396         DEBUGQUE("canque_again_outslot for edge %d returned %d\n",qedge->edge_num,ret);
397         return ret;
398 }
399
400 /**
401  * canque_set_filt - sets filter for specified edge
402  * @qedge: pointer to the edge
403  * @filtid: ID to set for the edge
404  * @filtmask: mask used for ID match check
405  * @filtflags: required filer flags
406  *
407  * Return Value: Negative value is returned if edge is in the process of delete.
408  */
409 int canque_set_filt(struct canque_edge_t *qedge,
410         unsigned long filtid, unsigned long filtmask, int filtflags)
411 {
412         int ret;
413         can_spin_irqflags_t flags;
414
415         can_spin_lock_irqsave(&qedge->fifo.fifo_lock,flags);
416         
417         if(!(filtflags&MSG_PROCESSLOCAL) && (processlocal<2))
418                 filtflags |= MSG_LOCAL_MASK;
419         
420         qedge->filtid=canque_filtid2internal(filtid, filtflags);
421         qedge->filtmask=canque_filtid2internal(filtmask, filtflags>>MSG_FILT_MASK_SHIFT);
422         
423         if(canque_fifo_test_fl(&qedge->fifo,DEAD)) ret=-1;
424         else ret=canque_fifo_test_and_set_fl(&qedge->fifo,BLOCK)?1:0;
425
426         can_spin_unlock_irqrestore(&qedge->fifo.fifo_lock,flags);
427         if(ret>=0){
428                 canque_notify_bothends(qedge,CANQUEUE_NOTIFY_FILTCH);
429         }
430         can_spin_lock_irqsave(&qedge->fifo.fifo_lock,flags);
431         if(!ret) canque_fifo_clear_fl(&qedge->fifo,BLOCK);
432         can_spin_unlock_irqrestore(&qedge->fifo.fifo_lock,flags);
433         
434         DEBUGQUE("canque_set_filt for edge %d, ID %ld, mask %ld, flags %d returned %d\n",
435                   qedge->edge_num,filtid,filtmask,filtflags,ret);
436         return ret;
437 }
438
439 /**
440  * canque_flush - fluesh all ready slots in the edge
441  * @qedge: pointer to the edge
442  *
443  * Tries to flush all allocated slots from the edge, but there could
444  * exist some slots associated to edge which are processed by input
445  * or output side and cannot be flushed at this moment.
446  * Return Value: The nonzero value indicates, that queue has not been
447  *      empty before the function call.
448  */
449 int canque_flush(struct canque_edge_t *qedge)
450 {
451         int ret;
452         can_spin_irqflags_t flags;
453
454         ret=canque_fifo_flush_slots(&qedge->fifo);
455         if(ret){
456                 canque_notify_inends(qedge,CANQUEUE_NOTIFY_EMPTY);
457                 canque_notify_inends(qedge,CANQUEUE_NOTIFY_SPACE);
458                 can_spin_lock_irqsave(&qedge->outends->ends_lock, flags);
459                 can_spin_lock(&qedge->fifo.fifo_lock);
460                 if(canque_fifo_test_fl(&qedge->fifo,EMPTY)){
461                         list_del(&qedge->activepeers);
462                         list_add(&qedge->activepeers,&qedge->outends->idle);
463                 }
464                 can_spin_unlock(&qedge->fifo.fifo_lock);
465                 can_spin_unlock_irqrestore(&qedge->outends->ends_lock, flags);
466         }
467         DEBUGQUE("canque_flush for edge %d returned %d\n",qedge->edge_num,ret);
468         return ret;
469 }
470
471 /**
472  * canqueue_ends_init_gen - subsystem independent routine to initialize ends state
473  * @qends: pointer to the ends structure
474  *
475  * Return Value: Cannot fail.
476  */
477 int canqueue_ends_init_gen(struct canque_ends_t *qends)
478 {
479         int i;
480         qends->ends_flags=0;
481         for(i=CANQUEUE_PRIO_NR;--i>=0;){
482                 INIT_LIST_HEAD(&qends->active[i]);
483         }
484         INIT_LIST_HEAD(&qends->idle);
485         INIT_LIST_HEAD(&qends->inlist);
486         INIT_LIST_HEAD(&qends->outlist);
487         can_spin_lock_init(&qends->ends_lock);
488         return 0;
489 }
490
491
492 /**
493  * canqueue_connect_edge - connect edge between two communication entities
494  * @qedge: pointer to edge
495  * @inends: pointer to ends the input of the edge should be connected to
496  * @outends: pointer to ends the output of the edge should be connected to
497  *
498  * Return Value: Negative value informs about failed operation.
499  */
500 int canqueue_connect_edge(struct canque_edge_t *qedge, struct canque_ends_t *inends, struct canque_ends_t *outends)
501 {
502         can_spin_irqflags_t flags;
503         if(qedge == NULL) return -1;
504         DEBUGQUE("canqueue_connect_edge %d\n",qedge->edge_num);
505         canque_edge_incref(qedge);
506         can_spin_lock_irqsave(&inends->ends_lock, flags);
507         can_spin_lock(&outends->ends_lock);
508         can_spin_lock(&qedge->fifo.fifo_lock);
509         qedge->inends=inends;
510         list_add(&qedge->inpeers,&inends->inlist);
511         qedge->outends=outends;
512         list_add(&qedge->outpeers,&outends->outlist);
513         list_add(&qedge->activepeers,&outends->idle);
514         can_spin_unlock(&qedge->fifo.fifo_lock);
515         can_spin_unlock(&outends->ends_lock);
516         can_spin_unlock_irqrestore(&inends->ends_lock, flags);
517         canque_notify_bothends(qedge, CANQUEUE_NOTIFY_ATTACH);
518
519         if(canque_fifo_test_and_set_fl(&qedge->fifo, READY))
520                 canque_edge_decref(qedge);
521         return 0;
522 }
523
524 /**
525  * canqueue_disconnect_edge - disconnect edge from communicating entities
526  * @qedge: pointer to edge
527  *
528  * Return Value: Negative value means, that edge is used by somebody
529  *      other and cannot be disconnected. Operation has to be delayed.
530  */
531 int canqueue_disconnect_edge(struct canque_edge_t *qedge)
532 {
533         int ret;
534         can_spin_irqflags_t flags;
535         struct canque_ends_t *inends, *outends;
536
537         inends=qedge->inends;
538         if(inends) can_spin_lock_irqsave(&inends->ends_lock,flags);
539         outends=qedge->outends;
540         if(outends) can_spin_lock(&outends->ends_lock);
541         can_spin_lock(&qedge->fifo.fifo_lock);
542         if(atomic_read(&qedge->edge_used)==0) {
543                 if(qedge->outends){
544                         list_del(&qedge->activepeers);
545                         mb(); /* memory barrier for list_empty use in canque_dead_func */
546                         list_del(&qedge->outpeers);
547                         qedge->outends=NULL;
548                 }
549                 if(qedge->inends){
550                         list_del(&qedge->inpeers);
551                         qedge->inends=NULL;
552                 }
553                 ret=1;
554         } else ret=-1;
555         can_spin_unlock(&qedge->fifo.fifo_lock);
556         if(outends) can_spin_unlock(&outends->ends_lock);
557         if(inends) can_spin_unlock_irqrestore(&inends->ends_lock,flags);
558         DEBUGQUE("canqueue_disconnect_edge %d returned %d\n",qedge->edge_num,ret);
559         return ret;
560 }
561
562
563 /**
564  * canqueue_block_inlist - block slot allocation of all outgoing edges of specified ends  
565  * @qends: pointer to ends structure
566  */
567 void canqueue_block_inlist(struct canque_ends_t *qends)
568 {
569         struct canque_edge_t *edge;
570
571         canque_for_each_inedge(qends, edge) {
572                 canque_fifo_set_fl(&edge->fifo,BLOCK);
573         }
574 }
575
576
577 /**
578  * canqueue_block_outlist - block slot allocation of all incoming edges of specified ends  
579  * @qends: pointer to ends structure
580  */
581 void canqueue_block_outlist(struct canque_ends_t *qends)
582 {
583         struct canque_edge_t *edge;
584
585         canque_for_each_outedge(qends, edge) {
586                 canque_fifo_set_fl(&edge->fifo,BLOCK);
587         }
588 }
589
590
591 /**
592  * canqueue_ends_kill_inlist - sends request to die to all outgoing edges
593  * @qends: pointer to ends structure
594  * @send_rest: select, whether already allocated slots should be processed
595  *      by FIFO output side
596  *
597  * Return Value: Non-zero value means, that not all edges could be immediately
598  *      disconnected and that ends structure memory release has to be delayed
599  */
600 int canqueue_ends_kill_inlist(struct canque_ends_t *qends, int send_rest)
601 {
602         struct canque_edge_t *edge;
603         
604         canque_for_each_inedge(qends, edge){
605                 canque_notify_bothends(edge, CANQUEUE_NOTIFY_DEAD_WANTED);
606                 if(send_rest){
607                         canque_edge_incref(edge);
608                         if(!canque_fifo_test_and_set_fl(&edge->fifo, FREEONEMPTY)){
609                                 if(!canque_fifo_test_fl(&edge->fifo, EMPTY))
610                                         continue;
611                                 if(!canque_fifo_test_and_clear_fl(&edge->fifo, FREEONEMPTY))
612                                         continue;
613                         }
614                         canque_edge_decref(edge);
615                 }
616         }
617         return list_empty(&qends->inlist)?0:1;
618 }
619
620
621 /**
622  * canqueue_ends_kill_outlist - sends request to die to all incoming edges
623  * @qends: pointer to ends structure
624  *
625  * Return Value: Non-zero value means, that not all edges could be immediately
626  *      disconnected and that ends structure memory release has to be delayed
627  */
628 int canqueue_ends_kill_outlist(struct canque_ends_t *qends)
629 {
630         struct canque_edge_t *edge;
631         
632         canque_for_each_outedge(qends, edge){
633                 canque_notify_bothends(edge, CANQUEUE_NOTIFY_DEAD_WANTED);
634         }
635         return list_empty(&qends->outlist)?0:1;
636 }
637
638
639 /**
640  * canqueue_ends_filt_conjuction - computes conjunction of incoming edges filters filters
641  * @qends: pointer to ends structure
642  * @qends: pointer the filter structure filled by computed filters conjunction
643  *
644  * Return Value: Number of incoming edges
645  */
646 int canqueue_ends_filt_conjuction(struct canque_ends_t *qends, struct canfilt_t *filt)
647 {
648         struct canque_edge_t *edge;
649         int cnt=0;
650         unsigned long filtid=0;
651         unsigned long filtmask=~0;
652         unsigned long local_only=canque_filtid2internal(0,MSG_LOCAL);
653
654         canque_for_each_inedge(qends, edge){
655                 /* skip edges processing only local messages */
656                 if(edge->filtid & edge->filtmask & local_only)
657                         continue;
658
659                 if(!cnt++)
660                         filtid = edge->filtid;
661                 else
662                         filtmask &= ~(filtid ^ edge->filtid);
663         
664                 filtmask &= edge->filtmask;
665         }
666         
667         filt->id = filtid & MSG_ID_MASK;
668         filt->mask = filtmask & MSG_ID_MASK;
669         filtid >>= 28;
670         filtmask >>= 28;
671         filt->flags = filtid & MSG_EXT;
672         if(filtmask & (MSG_EXT))
673                 filt->flags |= MSG_EXT_MASK;
674         if(filtid & (MSG_RTR<<1))
675                 filt->flags |= MSG_RTR<<1;
676         if(filtmask & (MSG_RTR<<1))
677                 filt->flags |= MSG_RTR_MASK;
678         return cnt;
679 }
680