RTEMS 7.0-rc1
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 return ( ( filter->id^id ) & filter->id_mask ) ||
182 ( ( filter->flags^flags ) & filter->flags_mask ) ? false : true;
183}
184
195static inline int rtems_can_queue_fifo_get_inslot(
196 struct rtems_can_queue_fifo *fifo,
197 struct rtems_can_queue_slot **slotp,
198 int cmd
199)
200{
201 struct rtems_can_queue_slot *slot;
202 rtems_mutex_lock( &fifo->fifo_lock );
203
204 /* Get the first free slot slot from free_list */
205 if ( ( slot = fifo->free_list ) == NULL ) {
206 rtems_can_queue_fifo_set_flag( fifo, RTEMS_CAN_FIFOF_OVERRUN );
207 rtems_can_queue_fifo_set_flag( fifo, RTEMS_CAN_FIFOF_FULL );
208 rtems_mutex_unlock( &fifo->fifo_lock );
209 *slotp = NULL;
210 return -1;
211 }
212
213 /* Adjust free slot list */
214 if ( ( fifo->free_list = slot->next ) == NULL ) {
215 rtems_can_queue_fifo_set_flag( fifo, RTEMS_CAN_FIFOF_FULL );
216 }
217
218 rtems_mutex_unlock( &fifo->fifo_lock );
219 *slotp = slot;
220 slot->slot_flags = cmd & RTEMS_CAN_SLOTF_CMD;
221
222 return 0;
223}
224
237static inline int rtems_can_queue_fifo_put_inslot(
238 struct rtems_can_queue_fifo *fifo,
239 struct rtems_can_queue_slot *slot
240)
241{
242 int ret = 0;
243
244 slot->next = NULL;
245 rtems_mutex_lock( &fifo->fifo_lock );
246 *fifo->tail = slot;
247 fifo->tail = &slot->next;
248
249 if ( rtems_can_queue_fifo_test_and_clear_fl( fifo, RTEMS_CAN_FIFOF_EMPTY ) ) {
250 /* Fifo has been empty before put */
252 }
253
254 if ( rtems_can_queue_fifo_test_and_clear_fl( fifo, RTEMS_CAN_FIFOF_INACTIVE ) ) {
255 /* Fifo has been empty before put */
257 }
258
259 if ( rtems_can_queue_fifo_test_and_clear_fl( fifo, RTEMS_CAN_FIFOF_OVERRUN ) ) {
260 /* RX overflow occured, report it with frame flag */
262 }
263
264 rtems_mutex_unlock( &fifo->fifo_lock );
265
266 return ret;
267}
268
279static inline int rtems_can_queue_fifo_abort_inslot(
280 struct rtems_can_queue_fifo *fifo,
281 struct rtems_can_queue_slot *slot
282)
283{
284 int ret = 0;
285
286 rtems_mutex_lock( &fifo->fifo_lock );
287 slot->next = fifo->free_list;
288 fifo->free_list = slot;
289 if ( rtems_can_queue_fifo_test_and_clear_fl( fifo, RTEMS_CAN_FIFOF_FULL ) ) {
291 }
292
293 rtems_mutex_unlock( &fifo->fifo_lock );
294
295 return ret;
296}
297
313static inline int rtems_can_queue_fifo_test_outslot(
314 struct rtems_can_queue_fifo *fifo,
315 struct rtems_can_queue_slot **slotp
316)
317{
318 int cmd;
319 struct rtems_can_queue_slot *slot;
320
321 rtems_mutex_lock( &fifo->fifo_lock );
322 if ( ( slot = fifo->head ) == NULL ) {
323 rtems_mutex_unlock( &fifo->fifo_lock );
324 *slotp = NULL;
325 return -1;
326 }
327
328 if ( ( fifo->head=slot->next ) == NULL ) {
329 fifo->tail = &fifo->head;
330 }
331
332 fifo->out_taken += 1;
333
334 rtems_mutex_unlock( &fifo->fifo_lock );
335
336 *slotp = slot;
337 cmd = slot->slot_flags;
338
339 return ( cmd & RTEMS_CAN_SLOTF_CMD );
340}
341
355static inline int rtems_can_queue_fifo_free_outslot(
356 struct rtems_can_queue_fifo *fifo,
357 struct rtems_can_queue_slot *slot
358)
359{
360 int ret = 0;
361
362 rtems_mutex_lock( &fifo->fifo_lock );
363 slot->next = fifo->free_list;
364 fifo->free_list = slot;
365 if ( rtems_can_queue_fifo_test_and_clear_fl( fifo, RTEMS_CAN_FIFOF_FULL ) ) {
367 }
368
369 fifo->out_taken -= 1;
370
371 if ( ( fifo->head ) == NULL ) {
372 rtems_can_queue_fifo_set_flag( fifo, RTEMS_CAN_FIFOF_INACTIVE );
374 if ( fifo->out_taken == 0 ) {
375 rtems_can_queue_fifo_set_flag( fifo, RTEMS_CAN_FIFOF_EMPTY );
377 }
378 }
379
380 rtems_mutex_unlock( &fifo->fifo_lock );
381
382 return ret;
383}
384
396static inline int rtems_can_queue_fifo_again_outslot(
397 struct rtems_can_queue_fifo *fifo,
398 struct rtems_can_queue_slot *slot
399)
400{
401 int ret = 0;
402
403 rtems_mutex_lock( &fifo->fifo_lock );
404 if ( ( slot->next = fifo->head ) == NULL ) {
405 fifo->tail = &slot->next;
407 }
408
409 fifo->out_taken -= 1;
410
411 fifo->head = slot;
412 rtems_mutex_unlock( &fifo->fifo_lock );
413
414 return ret;
415}
416
425static inline int rtems_can_queue_fifo_slot_size( int max_data_length )
426{
427 return RTEMS_ALIGN_UP(
428 offsetof( struct rtems_can_queue_slot, frame.data ) + max_data_length,
430 );
431}
432
443static inline void rtems_can_queue_notify_input_ends(
444 struct rtems_can_queue_edge *qedge,
445 int what
446)
447{
448 if ( qedge->input_ends ) {
449 if ( qedge->input_ends->notify ) {
450 qedge->input_ends->notify( qedge->input_ends, qedge,what );
451 }
452 }
453}
454
465static inline void rtems_can_queue_notify_output_ends(
466 struct rtems_can_queue_edge *qedge,
467 int what
468)
469{
470 if ( qedge->output_ends ) {
471 if ( qedge->output_ends->notify ) {
472 qedge->output_ends->notify( qedge->output_ends, qedge, what );
473 }
474 }
475}
476
486static inline void rtems_can_queue_notify_both_ends(
487 struct rtems_can_queue_edge *qedge,
488 int what
489)
490{
491 rtems_can_queue_notify_input_ends( qedge, what );
492 rtems_can_queue_notify_output_ends( qedge, what );
493}
494
508static inline void rtems_can_queue_activate_edge(
509 struct rtems_can_queue_ends *input_ends,
510 struct rtems_can_queue_edge *qedge
511)
512{
513 (void) input_ends;
514
515 struct rtems_can_queue_ends *output_ends = qedge->output_ends;
516
517 if ( qedge->edge_prio >= RTEMS_CAN_QUEUE_PRIO_NR ) {
518 qedge->edge_prio = RTEMS_CAN_QUEUE_PRIO_NR - 1;
519 }
520
521 if ( output_ends != NULL ) {
522 rtems_mutex_lock( &output_ends->ends_lock );
523 rtems_mutex_lock( &qedge->fifo.fifo_lock );
524 if ( qedge->peershead != &output_ends->active[qedge->edge_prio] ) {
525 if ( qedge->peershead != NULL ) {
526 TAILQ_REMOVE( qedge->peershead, qedge, activepeers );
527 }
528
529 TAILQ_INSERT_HEAD(
530 &output_ends->active[qedge->edge_prio],
531 qedge, activepeers
532 );
533 qedge->peershead = &output_ends->active[qedge->edge_prio];
534 }
535 rtems_mutex_unlock( &qedge->fifo.fifo_lock );
536 rtems_mutex_unlock( &output_ends->ends_lock );
537 }
538}
539
540static inline void rtems_can_queue_edge_to_idle_unprotected(
541 struct rtems_can_queue_ends *output_ends,
542 struct rtems_can_queue_edge *qedge
543)
544{
545 if ( qedge->peershead != NULL ) {
546 TAILQ_REMOVE( qedge->peershead, qedge, activepeers );
547 }
548 TAILQ_INSERT_TAIL( &output_ends->idle, qedge, activepeers );
549 qedge->peershead = &output_ends->idle;
550}
551
560static inline void rtems_can_queue_edge_incref(
561 struct rtems_can_queue_edge *edge
562)
563{
564 atomic_fetch_add( &edge->edge_used, 1 );
565}
566
567static inline void rtems_can_queue_do_edge_decref_body(
568 struct rtems_can_queue_edge *edge
569)
570{
571 int dead_fl = 0;
572 struct rtems_can_queue_ends *input_ends=edge->input_ends;
573 struct rtems_can_queue_ends *output_ends=edge->output_ends;
574
575 if ( input_ends < output_ends ) {
576 rtems_mutex_lock( &input_ends->ends_lock );
577 rtems_mutex_lock( &output_ends->ends_lock );
578 if ( atomic_fetch_sub( &edge->edge_used, 1 ) == 1 ) {
579 dead_fl = !rtems_can_queue_fifo_test_and_set_flag(
580 &edge->fifo,
582 );
583 }
584 rtems_mutex_unlock( &output_ends->ends_lock );
585 rtems_mutex_unlock( &input_ends->ends_lock );
586 } else {
587 rtems_mutex_lock( &output_ends->ends_lock );
588 if ( output_ends != input_ends ) {
589 rtems_mutex_lock( &input_ends->ends_lock );
590 }
591 if ( atomic_fetch_sub( &edge->edge_used, 1 ) == 1 ) {
592 dead_fl = !rtems_can_queue_fifo_test_and_set_flag(
593 &edge->fifo,
595 );
596 }
597 if ( output_ends != input_ends ) {
598 rtems_mutex_unlock( &input_ends->ends_lock );
599 }
600 rtems_mutex_unlock( &output_ends->ends_lock );
601 }
602
603 if ( dead_fl ) {
605 }
606}
607
620static inline void rtems_can_queue_edge_decref(
621 struct rtems_can_queue_edge *edge
622)
623{
624 unsigned int x;
625
626 x = atomic_load_explicit( &edge->edge_used, memory_order_relaxed );
627
628 do {
629 if ( x <= 1 ) {
630 return rtems_can_queue_do_edge_decref( edge );
631 }
632 } while( !atomic_compare_exchange_strong(&edge->edge_used, &x, x-1 ) );
633}
634
635static inline struct rtems_can_queue_edge *rtems_can_queue_first_inedge(
636 struct rtems_can_queue_ends *qends
637)
638{
639 struct rtems_can_queue_edge *edge;
640
641 rtems_mutex_lock( &qends->ends_lock );
642 edge = TAILQ_FIRST( &qends->inlist );
643
644 while ( edge && rtems_can_queue_fifo_test_flag( &edge->fifo, RTEMS_CAN_FIFOF_DEAD ) ) {
645 edge = TAILQ_NEXT( edge, input_peers );
646 }
647 if ( edge )
648 rtems_can_queue_edge_incref( edge );
649
650 rtems_mutex_unlock( &qends->ends_lock );
651 return edge;
652}
653
654
655static inline struct rtems_can_queue_edge *rtems_can_queue_next_inedge(
656 struct rtems_can_queue_ends *qends,
657 struct rtems_can_queue_edge *edge
658)
659{
660 struct rtems_can_queue_edge *next;
661
662 rtems_mutex_lock( &qends->ends_lock );
663 next = TAILQ_NEXT( edge, input_peers );
664
665 while ( next && rtems_can_queue_fifo_test_flag( &next->fifo, RTEMS_CAN_FIFOF_DEAD ) ) {
666 next = TAILQ_NEXT( next, input_peers );
667 }
668 if ( next )
669 rtems_can_queue_edge_incref( next );
670
671 rtems_mutex_unlock( &qends->ends_lock );
672 rtems_can_queue_edge_decref( edge );
673 return next;
674}
675
676#define rtems_can_queue_for_each_inedge( qends, edge ) \
677 for ( \
678 edge = rtems_can_queue_first_inedge( qends ); \
679 edge; \
680 edge = rtems_can_queue_next_inedge( qends, edge ) )
681
682static inline
683struct rtems_can_queue_edge *can_queue_first_outedge(
684 struct rtems_can_queue_ends *qends
685)
686{
687 struct rtems_can_queue_edge *edge;
688
689 rtems_mutex_lock( &qends->ends_lock );
690 edge = TAILQ_FIRST( &qends->outlist );
691
692 while ( edge && rtems_can_queue_fifo_test_flag( &edge->fifo, RTEMS_CAN_FIFOF_DEAD ) ) {
693 edge = TAILQ_NEXT( edge, output_peers );
694 }
695 if ( edge )
696 rtems_can_queue_edge_incref( edge );
697
698 rtems_mutex_unlock( &qends->ends_lock );
699 return edge;
700}
701
702static inline
703struct rtems_can_queue_edge *rtems_can_queue_next_outedge(
704 struct rtems_can_queue_ends *qends,
705 struct rtems_can_queue_edge *edge
706)
707{
708 struct rtems_can_queue_edge *next;
709
710 rtems_mutex_lock( &qends->ends_lock );
711 next = TAILQ_NEXT( edge, output_peers );
712
713 while ( next && rtems_can_queue_fifo_test_flag( &next->fifo, RTEMS_CAN_FIFOF_DEAD ) ) {
714 next = TAILQ_NEXT( next, output_peers );
715 }
716 if ( next )
717 rtems_can_queue_edge_incref( next );
718
719 rtems_mutex_unlock( &qends->ends_lock );
720 rtems_can_queue_edge_decref( edge );
721 return next;
722}
723
724#define rtems_can_queue_for_each_outedge( qends, edge ) \
725 for ( \
726 edge = can_queue_first_outedge( qends ); \
727 edge; \
728 edge = rtems_can_queue_next_outedge( qends, edge ) )
729
730
731#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:138
void rtems_can_queue_do_edge_decref(struct rtems_can_queue_edge *qedge)
This function decrements the edge user counter.
Definition: can-queue.c:99
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
#define RTEMS_ALIGN_UP(_value, _alignment)
Aligns up the value to the alignment.
Definition: basedefs.h:141
#define RTEMS_ALIGNOF(_type_name)
Gets the alignment requirement of the type.
Definition: basedefs.h:176
Provide printf() PRIxxx Constante Beyond Standards.
This header file defines the RTEMS Classic API.
Header File for Status Checks.
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
This header file provides the API of Self-Contained Objects.
Timespec API.