RTEMS CAN/CAN FD Stack
Loading...
Searching...
No Matches
can-impl.h
Go to the documentation of this file.
1/* SPDX-License-Identifier: BSD-2-Clause OR Apache-2.0 OR GPL-2.0-or-later */
2
15/*
16 * Copyright (C) 2023-2024 Michal Lenc <michallenc@seznam.cz>
17 * Copyright (C) 2002-2009 DCE FEE CTU Prague
18 * Copyright (C) 2002-2024 Pavel Pisa <pisa@cmp.felk.cvut.cz>
19 *
20 * Redistribution and use in source and binary forms, with or without
21 * modification, are permitted provided that the following conditions
22 * are met:
23 * 1. Redistributions of source code must retain the above copyright
24 * notice, this list of conditions and the following disclaimer.
25 * 2. Redistributions in binary form must reproduce the above copyright
26 * notice, this list of conditions and the following disclaimer in the
27 * documentation and/or other materials provided with the distribution.
28 *
29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
30 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
33 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
34 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
35 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
36 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
37 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
39 * POSSIBILITY OF SUCH DAMAGE.
40 */
41
42#ifndef __DEV_CAN_CAN_IMPL_H
43#define __DEV_CAN_CAN_IMPL_H
44
45#include <stdatomic.h>
46#include <inttypes.h>
47#include <sys/queue.h>
48#include <rtems.h>
49#include <rtems/timespec.h>
50#include <rtems/status-checks.h>
51#include <rtems/thread.h>
52
53#include <dev/can/can-frame.h>
54#include <dev/can/can-filter.h>
55#include <dev/can/can-queue.h>
56
67static inline int rtems_can_queue_fifo_test_flag(
68 struct rtems_can_queue_fifo *fifo,
69 unsigned int flag
70)
71{
72 return ( atomic_load( &fifo->fifo_flags ) & flag ) == flag;
73}
74
84static inline void rtems_can_queue_fifo_set_flag(
85 struct rtems_can_queue_fifo *fifo,
86 int flag
87)
88{
89 atomic_fetch_or( &fifo->fifo_flags, flag );
90}
91
101static inline void rtems_can_queue_fifo_clear_flag(
102 struct rtems_can_queue_fifo *fifo,
103 int flag
104)
105{
106 atomic_fetch_and( &fifo->fifo_flags, ~flag );
107}
108
119static inline int rtems_can_queue_fifo_test_and_set_flag(
120 struct rtems_can_queue_fifo *fifo,
121 int flag
122)
123{
124 return ( atomic_fetch_or( &fifo->fifo_flags, flag ) & flag ) ? 1 : 0;
125}
126
137static inline int rtems_can_queue_fifo_test_and_clear_fl(
138 struct rtems_can_queue_fifo *fifo,
139 int flag
140)
141{
142 return ( atomic_fetch_and( &fifo->fifo_flags, ~flag ) & flag ) ? 1 : 0;
143}
144
155static inline int rtems_can_queue_fifo_out_is_ready_unprotected(
156 struct rtems_can_queue_fifo *fifo
157)
158{
159 return ( ( fifo->head ) != NULL ) ? 1 : 0;
160}
161
176static inline bool rtems_can_queue_filter_match(
177 struct rtems_can_filter *filter,
178 uint32_t id,
179 uint32_t flags
180)
181{
182 return ( ( filter->id ^ id ) & filter->id_mask ) ||
183 ( ( filter->flags ^ flags ) & filter->flags_mask )
184 ? false
185 : true;
186}
187
198static inline int rtems_can_queue_fifo_get_inslot(
199 struct rtems_can_queue_fifo *fifo,
200 struct rtems_can_queue_slot **slotp,
201 int cmd
202)
203{
204 struct rtems_can_queue_slot *slot;
205 rtems_mutex_lock( &fifo->fifo_lock );
206
207 /* Get the first free slot slot from free_list */
208 if ( ( slot = fifo->free_list ) == NULL ) {
209 rtems_can_queue_fifo_set_flag( fifo, RTEMS_CAN_FIFOF_OVERRUN );
210 rtems_can_queue_fifo_set_flag( fifo, RTEMS_CAN_FIFOF_FULL );
211 rtems_mutex_unlock( &fifo->fifo_lock );
212 *slotp = NULL;
213 return -1;
214 }
215
216 /* Adjust free slot list */
217 if ( ( fifo->free_list = slot->next ) == NULL ) {
218 rtems_can_queue_fifo_set_flag( fifo, RTEMS_CAN_FIFOF_FULL );
219 }
220
221 rtems_mutex_unlock( &fifo->fifo_lock );
222 *slotp = slot;
223 slot->slot_flags = cmd & RTEMS_CAN_SLOTF_CMD;
224
225 return 0;
226}
227
240static inline int rtems_can_queue_fifo_put_inslot(
241 struct rtems_can_queue_fifo *fifo,
242 struct rtems_can_queue_slot *slot
243)
244{
245 int ret = 0;
246
247 slot->next = NULL;
248 rtems_mutex_lock( &fifo->fifo_lock );
249 *fifo->tail = slot;
250 fifo->tail = &slot->next;
251
252 if (
253 rtems_can_queue_fifo_test_and_clear_fl( fifo, RTEMS_CAN_FIFOF_EMPTY )
254 ) {
255 /* Fifo has been empty before put */
257 }
258
259 if (
260 rtems_can_queue_fifo_test_and_clear_fl( fifo, RTEMS_CAN_FIFOF_INACTIVE )
261 ) {
262 /* Fifo has been empty before put */
264 }
265
266 if (
267 rtems_can_queue_fifo_test_and_clear_fl( fifo, RTEMS_CAN_FIFOF_OVERRUN )
268 ) {
269 /* RX overflow occured, report it with frame flag */
271 }
272
273 rtems_mutex_unlock( &fifo->fifo_lock );
274
275 return ret;
276}
277
288static inline int rtems_can_queue_fifo_abort_inslot(
289 struct rtems_can_queue_fifo *fifo,
290 struct rtems_can_queue_slot *slot
291)
292{
293 int ret = 0;
294
295 rtems_mutex_lock( &fifo->fifo_lock );
296 slot->next = fifo->free_list;
297 fifo->free_list = slot;
298 if ( rtems_can_queue_fifo_test_and_clear_fl( fifo, RTEMS_CAN_FIFOF_FULL ) ) {
300 }
301
302 rtems_mutex_unlock( &fifo->fifo_lock );
303
304 return ret;
305}
306
322static inline int rtems_can_queue_fifo_test_outslot(
323 struct rtems_can_queue_fifo *fifo,
324 struct rtems_can_queue_slot **slotp
325)
326{
327 int cmd;
328 struct rtems_can_queue_slot *slot;
329
330 rtems_mutex_lock( &fifo->fifo_lock );
331 if ( ( slot = fifo->head ) == NULL ) {
332 rtems_mutex_unlock( &fifo->fifo_lock );
333 *slotp = NULL;
334 return -1;
335 }
336
337 if ( ( fifo->head = slot->next ) == NULL ) {
338 fifo->tail = &fifo->head;
339 }
340
341 fifo->out_taken += 1;
342
343 rtems_mutex_unlock( &fifo->fifo_lock );
344
345 *slotp = slot;
346 cmd = slot->slot_flags;
347
348 return ( cmd & RTEMS_CAN_SLOTF_CMD );
349}
350
364static inline int rtems_can_queue_fifo_free_outslot(
365 struct rtems_can_queue_fifo *fifo,
366 struct rtems_can_queue_slot *slot
367)
368{
369 int ret = 0;
370
371 rtems_mutex_lock( &fifo->fifo_lock );
372 slot->next = fifo->free_list;
373 fifo->free_list = slot;
374 if ( rtems_can_queue_fifo_test_and_clear_fl( fifo, RTEMS_CAN_FIFOF_FULL ) ) {
376 }
377
378 fifo->out_taken -= 1;
379
380 if ( ( fifo->head ) == NULL ) {
381 rtems_can_queue_fifo_set_flag( fifo, RTEMS_CAN_FIFOF_INACTIVE );
383 if ( fifo->out_taken == 0 ) {
384 rtems_can_queue_fifo_set_flag( fifo, RTEMS_CAN_FIFOF_EMPTY );
386 }
387 }
388
389 rtems_mutex_unlock( &fifo->fifo_lock );
390
391 return ret;
392}
393
405static inline int rtems_can_queue_fifo_again_outslot(
406 struct rtems_can_queue_fifo *fifo,
407 struct rtems_can_queue_slot *slot
408)
409{
410 int ret = 0;
411
412 rtems_mutex_lock( &fifo->fifo_lock );
413 if ( ( slot->next = fifo->head ) == NULL ) {
414 fifo->tail = &slot->next;
416 }
417
418 fifo->out_taken -= 1;
419
420 fifo->head = slot;
421 rtems_mutex_unlock( &fifo->fifo_lock );
422
423 return ret;
424}
425
434static inline int rtems_can_queue_fifo_slot_size( int max_data_length )
435{
436 return RTEMS_ALIGN_UP(
437 offsetof( struct rtems_can_queue_slot, frame.data ) + max_data_length,
438 RTEMS_ALIGNOF( struct rtems_can_queue_slot )
439 );
440}
441
452static inline void rtems_can_queue_notify_input_ends(
453 struct rtems_can_queue_edge *qedge,
454 int what
455)
456{
457 if ( qedge->input_ends ) {
458 if ( qedge->input_ends->notify ) {
459 qedge->input_ends->notify( qedge->input_ends, qedge, what );
460 }
461 }
462}
463
474static inline void rtems_can_queue_notify_output_ends(
475 struct rtems_can_queue_edge *qedge,
476 int what
477)
478{
479 if ( qedge->output_ends ) {
480 if ( qedge->output_ends->notify ) {
481 qedge->output_ends->notify( qedge->output_ends, qedge, what );
482 }
483 }
484}
485
495static inline void rtems_can_queue_notify_both_ends(
496 struct rtems_can_queue_edge *qedge,
497 int what
498)
499{
500 rtems_can_queue_notify_input_ends( qedge, what );
501 rtems_can_queue_notify_output_ends( qedge, what );
502}
503
517static inline void rtems_can_queue_activate_edge(
518 struct rtems_can_queue_ends *input_ends,
519 struct rtems_can_queue_edge *qedge
520)
521{
522 (void) input_ends;
523
524 struct rtems_can_queue_ends *output_ends = qedge->output_ends;
525
526 if ( qedge->edge_prio >= RTEMS_CAN_QUEUE_PRIO_NR ) {
527 qedge->edge_prio = RTEMS_CAN_QUEUE_PRIO_NR - 1;
528 }
529
530 if ( output_ends != NULL ) {
531 rtems_mutex_lock( &output_ends->ends_lock );
532 rtems_mutex_lock( &qedge->fifo.fifo_lock );
533 if ( qedge->peershead != &output_ends->active[ qedge->edge_prio ] ) {
534 if ( qedge->peershead != NULL ) {
535 TAILQ_REMOVE( qedge->peershead, qedge, activepeers );
536 }
537
538 TAILQ_INSERT_HEAD(
539 &output_ends->active[ qedge->edge_prio ],
540 qedge,
541 activepeers
542 );
543 qedge->peershead = &output_ends->active[ qedge->edge_prio ];
544 }
545 rtems_mutex_unlock( &qedge->fifo.fifo_lock );
546 rtems_mutex_unlock( &output_ends->ends_lock );
547 }
548}
549
550static inline void rtems_can_queue_edge_to_idle_unprotected(
551 struct rtems_can_queue_ends *output_ends,
552 struct rtems_can_queue_edge *qedge
553)
554{
555 if ( qedge->peershead != NULL ) {
556 TAILQ_REMOVE( qedge->peershead, qedge, activepeers );
557 }
558 TAILQ_INSERT_TAIL( &output_ends->idle, qedge, activepeers );
559 qedge->peershead = &output_ends->idle;
560}
561
570static inline void rtems_can_queue_edge_incref(
571 struct rtems_can_queue_edge *edge
572)
573{
574 atomic_fetch_add( &edge->edge_used, 1 );
575}
576
577static inline void rtems_can_queue_do_edge_decref_body(
578 struct rtems_can_queue_edge *edge
579)
580{
581 int dead_fl = 0;
582 struct rtems_can_queue_ends *input_ends = edge->input_ends;
583 struct rtems_can_queue_ends *output_ends = edge->output_ends;
584
585 if ( input_ends < output_ends ) {
586 rtems_mutex_lock( &input_ends->ends_lock );
587 rtems_mutex_lock( &output_ends->ends_lock );
588 if ( atomic_fetch_sub( &edge->edge_used, 1 ) == 1 ) {
589 dead_fl = !rtems_can_queue_fifo_test_and_set_flag(
590 &edge->fifo,
592 );
593 }
594 rtems_mutex_unlock( &output_ends->ends_lock );
595 rtems_mutex_unlock( &input_ends->ends_lock );
596 } else {
597 rtems_mutex_lock( &output_ends->ends_lock );
598 if ( output_ends != input_ends ) {
599 rtems_mutex_lock( &input_ends->ends_lock );
600 }
601 if ( atomic_fetch_sub( &edge->edge_used, 1 ) == 1 ) {
602 dead_fl = !rtems_can_queue_fifo_test_and_set_flag(
603 &edge->fifo,
605 );
606 }
607 if ( output_ends != input_ends ) {
608 rtems_mutex_unlock( &input_ends->ends_lock );
609 }
610 rtems_mutex_unlock( &output_ends->ends_lock );
611 }
612
613 if ( dead_fl ) {
615 }
616}
617
630static inline void rtems_can_queue_edge_decref(
631 struct rtems_can_queue_edge *edge
632)
633{
634 unsigned int x;
635
636 x = atomic_load_explicit( &edge->edge_used, memory_order_relaxed );
637
638 do {
639 if ( x <= 1 ) {
640 return rtems_can_queue_do_edge_decref( edge );
641 }
642 } while ( !atomic_compare_exchange_strong( &edge->edge_used, &x, x - 1 ) );
643}
644
645static inline struct rtems_can_queue_edge *rtems_can_queue_first_inedge(
646 struct rtems_can_queue_ends *qends
647)
648{
649 struct rtems_can_queue_edge *edge;
650
651 rtems_mutex_lock( &qends->ends_lock );
652 edge = TAILQ_FIRST( &qends->inlist );
653
654 while (
655 edge && rtems_can_queue_fifo_test_flag( &edge->fifo, RTEMS_CAN_FIFOF_DEAD )
656 ) {
657 edge = TAILQ_NEXT( edge, input_peers );
658 }
659 if ( edge ) {
660 rtems_can_queue_edge_incref( edge );
661 }
662
663 rtems_mutex_unlock( &qends->ends_lock );
664 return edge;
665}
666
667static inline struct rtems_can_queue_edge *rtems_can_queue_next_inedge(
668 struct rtems_can_queue_ends *qends,
669 struct rtems_can_queue_edge *edge
670)
671{
672 struct rtems_can_queue_edge *next;
673
674 rtems_mutex_lock( &qends->ends_lock );
675 next = TAILQ_NEXT( edge, input_peers );
676
677 while (
678 next && rtems_can_queue_fifo_test_flag( &next->fifo, RTEMS_CAN_FIFOF_DEAD )
679 ) {
680 next = TAILQ_NEXT( next, input_peers );
681 }
682 if ( next ) {
683 rtems_can_queue_edge_incref( next );
684 }
685
686 rtems_mutex_unlock( &qends->ends_lock );
687 rtems_can_queue_edge_decref( edge );
688 return next;
689}
690
691#define rtems_can_queue_for_each_inedge( qends, edge ) \
692 for ( \
693 edge = rtems_can_queue_first_inedge( qends ); edge; \
694 edge = rtems_can_queue_next_inedge( qends, edge ) \
695 )
696
697static inline struct rtems_can_queue_edge *can_queue_first_outedge(
698 struct rtems_can_queue_ends *qends
699)
700{
701 struct rtems_can_queue_edge *edge;
702
703 rtems_mutex_lock( &qends->ends_lock );
704 edge = TAILQ_FIRST( &qends->outlist );
705
706 while (
707 edge && rtems_can_queue_fifo_test_flag( &edge->fifo, RTEMS_CAN_FIFOF_DEAD )
708 ) {
709 edge = TAILQ_NEXT( edge, output_peers );
710 }
711 if ( edge ) {
712 rtems_can_queue_edge_incref( edge );
713 }
714
715 rtems_mutex_unlock( &qends->ends_lock );
716 return edge;
717}
718
719static inline struct rtems_can_queue_edge *rtems_can_queue_next_outedge(
720 struct rtems_can_queue_ends *qends,
721 struct rtems_can_queue_edge *edge
722)
723{
724 struct rtems_can_queue_edge *next;
725
726 rtems_mutex_lock( &qends->ends_lock );
727 next = TAILQ_NEXT( edge, output_peers );
728
729 while (
730 next && rtems_can_queue_fifo_test_flag( &next->fifo, RTEMS_CAN_FIFOF_DEAD )
731 ) {
732 next = TAILQ_NEXT( next, output_peers );
733 }
734 if ( next ) {
735 rtems_can_queue_edge_incref( next );
736 }
737
738 rtems_mutex_unlock( &qends->ends_lock );
739 rtems_can_queue_edge_decref( edge );
740 return next;
741}
742
743#define rtems_can_queue_for_each_outedge( qends, edge ) \
744 for ( \
745 edge = can_queue_first_outedge( qends ); edge; \
746 edge = rtems_can_queue_next_outedge( qends, edge ) \
747 )
748
749#endif /* __DEV_CAN_CAN_IMPL_H */
This header file is part of CAN/CAN FD bus common support. It implements structure that represents fi...
This header file is part of CAN/CAN FD bus common support. It implements CAN frame structure and rela...
void rtems_can_queue_edge_do_dead(struct rtems_can_queue_edge *qedge)
This function disconnects the edge.
Definition: can-quekern.c:139
void rtems_can_queue_do_edge_decref(struct rtems_can_queue_edge *qedge)
This function decrements the edge user counter.
Definition: can-queue.c:101
This file is part of CAN/CAN FD bus common support and implements CAN FIFOs and generic hubs/ends for...
#define RTEMS_CAN_FIFOF_DEAD
This is used when FIFO is beeing destroyed.
Definition: can-queue.h:173
#define RTEMS_CAN_FIFOF_OVERRUN
This indicates attempt to acquire new slot, when FIFO is full.
Definition: can-queue.h:161
#define RTEMS_CAN_SLOTF_CMD
Macro for command associated with allocated slot.
Definition: can-queue.h:80
#define RTEMS_CAN_FIFOF_FULL
This indicates FIFO full state.
Definition: can-queue.h:165
#define RTEMS_CAN_FIFOF_INACTIVE
This indicates FIFO is inactive.
Definition: can-queue.h:177
#define RTEMS_CAN_FIFOF_EMPTY
This indicates no allocated slot in the FIFO.
Definition: can-queue.h:169
#define CAN_FRAME_FIFO_OVERFLOW
Represents local FIFO overflow.
Definition: can-frame.h:117
uint16_t flags
This member holds the CAN flags. These are used to pass additional information between driver and app...
Definition: can-frame.h:522
struct can_frame_header header
This member stores the structure can_frame_header representing CAN header.
Definition: can-frame.h:539
uint8_t data[CAN_FRAME_MAX_DLEN]
This member stores CAN data.
Definition: can-frame.h:543
This structure is used to represent CAN ID and flags in one unified structure.
Definition: can-filter.h:50
uint32_t id
This member is a bitfield that holds required CAN identifier values to assign CAN frame to the FIFO q...
Definition: can-filter.h:55
uint32_t flags_mask
This member is a bitfield that holds CAN flags forbidden in CAN frame. If the frame has some of these...
Definition: can-filter.h:76
uint32_t id_mask
This member is a bitfield that holds forbidden CAN identifier values. If the frame has identifier in ...
Definition: can-filter.h:61
uint32_t flags
This member is a bitfield that holds CAN flags required in CAN frame to be assigned to the FIFO queue...
Definition: can-filter.h:68
This structure represents one direction connection from messages source ( input_ends) to message cons...
Definition: can-queue.h:231
struct rtems_can_queue_edges_list * peershead
This member holds the pointer to the activepeers head.
Definition: can-queue.h:263
int edge_prio
This member holds the the assigned queue priority from the range 0 to RTEMS_CAN_QUEUE_PRIO_NR - 1.
Definition: can-queue.h:283
struct rtems_can_queue_ends * output_ends
This member holds the pointer to the FIFO output side terminal ( rtems_can_queue_ends ).
Definition: can-queue.h:273
atomic_uint edge_used
This member holds the atomic usage counter, mainly used for safe destruction of the edge.
Definition: can-queue.h:278
struct rtems_can_queue_ends * input_ends
This member holds the pointer to the FIFO input side terminal ( rtems_can_queue_ends ).
Definition: can-queue.h:268
struct rtems_can_queue_fifo fifo
This member holds place where primitive rtems_can_queue_fifo FIFO is located.
Definition: can-queue.h:236
This structure represents place to connect edges to for CAN communication entity. The zero,...
Definition: can-queue.h:299
struct rtems_can_queue_edges_list active[RTEMS_CAN_QUEUE_PRIO_NR]
This member holds the array of the lists of active edges directed to the ends structure.
Definition: can-queue.h:304
struct rtems_can_queue_edges_list outlist
This member holds the list of all incoming edges output sides. Each of there edges is listed on one o...
Definition: can-queue.h:318
struct rtems_can_queue_edges_list idle
This member holds the list of the edges directed to the ends structure with empty FIFOs.
Definition: can-queue.h:309
rtems_mutex ends_lock
This member holds the lock synchronizing operations between threads accessing the ends.
Definition: can-queue.h:323
struct rtems_can_queue_edges_list inlist
This member holds the list of outgoing edges input sides.
Definition: can-queue.h:313
void(* notify)(struct rtems_can_queue_ends *qends, struct rtems_can_queue_edge *qedge, int what)
pointer to notify procedure. The next state changes are notified.
Definition: can-queue.h:350
This structure represents CAN FIFO queue. It is implemented as a single linked list of slots prepared...
Definition: can-queue.h:88
unsigned int out_taken
This member holds the number of elements in the fifo.
Definition: can-queue.h:103
struct rtems_can_queue_slot * free_list
This member holds the pointer to list of the free slots associated with queue.
Definition: can-queue.h:121
rtems_mutex fifo_lock
This member holds the lock to ensure atomicity of slot manipulation operations.
Definition: can-queue.h:139
struct rtems_can_queue_slot * head
This member holds the pointer to the FIFO head, oldest slot.
Definition: can-queue.h:111
atomic_uint fifo_flags
This field holds global flags describing state of the FIFO.
Definition: can-queue.h:92
struct rtems_can_queue_slot ** tail
This member holds the pointer to the location, where pointer to newly inserted slot should be added.
Definition: can-queue.h:116
This structure represents one CAN message slot in the CAN FIFO queue.
Definition: can-queue.h:60
atomic_uint slot_flags
Space for flags and optional command describing action associated with slot data.
Definition: can-queue.h:69
struct can_frame frame
This member holds can_frame structure representing one CAN frame/message.
Definition: can-queue.h:74
struct rtems_can_queue_slot * next
Pointer to next/younger slot.
Definition: can-queue.h:64