@@ -33,20 +33,6 @@ LOG_MODULE_REGISTER(can_mcux_flexcan, CONFIG_CAN_LOG_LEVEL);
3333#define RX_START_IDX 0
3434#endif
3535
36- /* The maximum number of message buffers for concurrent active instances */
37- #ifdef CONFIG_CAN_MAX_MB
38- #define MCUX_FLEXCAN_MAX_MB CONFIG_CAN_MAX_MB
39- #else
40- #define MCUX_FLEXCAN_MAX_MB FSL_FEATURE_FLEXCAN_HAS_MESSAGE_BUFFER_MAX_NUMBERn(0)
41- #endif
42-
43- /*
44- * RX message buffers (filters) will take up the first N message
45- * buffers. The rest are available for TX use.
46- */
47- #define MCUX_FLEXCAN_MAX_RX (CONFIG_CAN_MAX_FILTER + RX_START_IDX)
48- #define MCUX_FLEXCAN_MAX_TX (MCUX_FLEXCAN_MAX_MB - MCUX_FLEXCAN_MAX_RX)
49-
5036/*
5137 * Convert from RX message buffer index to allocated filter ID and
5238 * vice versa.
@@ -58,8 +44,8 @@ LOG_MODULE_REGISTER(can_mcux_flexcan, CONFIG_CAN_LOG_LEVEL);
5844 * Convert from TX message buffer index to allocated TX ID and vice
5945 * versa.
6046 */
61- #define TX_MBIDX_TO_ALLOC_IDX (x ) (x - MCUX_FLEXCAN_MAX_RX )
62- #define ALLOC_IDX_TO_TXMB_IDX (x ) (x + MCUX_FLEXCAN_MAX_RX )
47+ #define TX_MBIDX_TO_ALLOC_IDX (x ) (x - data->max_rx_mb )
48+ #define ALLOC_IDX_TO_TXMB_IDX (x ) (x + data->max_rx_mb )
6349
6450/* Convert from back from FLEXCAN IDs to Zephyr CAN IDs. */
6551#define FLEXCAN_ID_TO_CAN_ID_STD (id ) \
@@ -79,6 +65,7 @@ struct mcux_flexcan_config {
7965 const struct device * clock_dev ;
8066 clock_control_subsys_t clock_subsys ;
8167 int clk_source ;
68+ uint16_t max_mb ;
8269#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD
8370 bool flexcan_fd ;
8471#endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */
@@ -113,16 +100,24 @@ struct mcux_flexcan_data {
113100 const struct device * dev ;
114101 flexcan_handle_t handle ;
115102
116- ATOMIC_DEFINE (rx_allocs , MCUX_FLEXCAN_MAX_RX );
117- struct k_mutex rx_mutex ;
118- struct mcux_flexcan_rx_callback rx_cbs [MCUX_FLEXCAN_MAX_RX ];
119-
120- ATOMIC_DEFINE (tx_allocs , MCUX_FLEXCAN_MAX_TX );
121- struct k_sem tx_allocs_sem ;
122- struct k_mutex tx_mutex ;
123- struct mcux_flexcan_tx_callback tx_cbs [MCUX_FLEXCAN_MAX_TX ];
124103 enum can_state state ;
125104 struct can_timing timing ;
105+
106+ uint32_t max_tx_mb ;
107+ uint32_t max_rx_mb ;
108+
109+ struct k_heap instance_heap ;
110+ uint8_t heap_buffer [CONFIG_CAN_MCUX_FLEXCAN_HEAP_SIZE ];
111+
112+ atomic_t * rx_allocs ;
113+ atomic_t * tx_allocs ;
114+ struct mcux_flexcan_rx_callback * rx_cbs ;
115+ struct mcux_flexcan_tx_callback * tx_cbs ;
116+
117+ struct k_mutex rx_mutex ;
118+ struct k_mutex tx_mutex ;
119+ struct k_sem tx_allocs_sem ;
120+
126121#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD
127122 struct can_timing timing_data ;
128123#endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */
@@ -133,6 +128,118 @@ static inline CAN_Type *get_base(const struct device *dev)
133128 return (CAN_Type * )DEVICE_MMIO_NAMED_GET (dev , flexcan_mmio );
134129}
135130
131+ static int mcux_flexcan_get_mb_config (const struct device * dev , uint32_t * max_mb ,
132+ uint32_t * max_rx , uint32_t * max_tx )
133+ {
134+ const struct mcux_flexcan_config * config = dev -> config ;
135+
136+ #ifdef CONFIG_CAN_MCUX_FLEXCAN_FD
137+ /*
138+ * When CAN FD is enabled, FlexCAN RAM can be partitioned into several blocks.
139+ * Each block can accommodate 7 message buffers if payload size is 64-byte.
140+ * Each block can accommodate 32 message buffers if payload size is 8-byte.
141+ * First calculate how many RAM blocks each FlexCAN instance support, then get
142+ * maximum accommodated message buffers under 64-byte payload size.
143+ */
144+ if (config -> flexcan_fd ) {
145+ /* For FlexCAN FD instances with 64-byte payload */
146+ * max_mb = config -> max_mb / 32U * 7U ;
147+ }
148+ else {
149+ /*
150+ * For non-FD FlexCAN instances.
151+ * Some platforms have both classical CAN and CAN FD instances.
152+ * In this case, use the maximum message buffers.
153+ */
154+ * max_mb = config -> max_mb ;
155+ }
156+ #else
157+ * max_mb = config -> max_mb ;
158+ #endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */
159+
160+ /*
161+ * RX message buffers (filters) will take up the first N message
162+ * buffers. The rest are available for TX use.
163+ */
164+ * max_rx = (CONFIG_CAN_MAX_FILTER + RX_START_IDX );
165+
166+ if (* max_mb < * max_rx ) {
167+ LOG_ERR ("Insufficient message buffers for RX filters" );
168+ return - EINVAL ;
169+ }
170+
171+ * max_tx = * max_mb - * max_rx ;
172+
173+ return 0 ;
174+ }
175+
176+ static int mcux_flexcan_allocate_memory (const struct device * dev )
177+ {
178+ struct mcux_flexcan_data * data = dev -> data ;
179+ size_t rx_bitmap_size , tx_bitmap_size ;
180+ size_t rx_cb_array_size , tx_cb_array_size ;
181+ size_t total_size ;
182+
183+ rx_bitmap_size = ATOMIC_BITMAP_SIZE (data -> max_rx_mb ) * sizeof (atomic_t );
184+ tx_bitmap_size = ATOMIC_BITMAP_SIZE (data -> max_tx_mb ) * sizeof (atomic_t );
185+ rx_cb_array_size = data -> max_rx_mb * sizeof (struct mcux_flexcan_rx_callback );
186+ tx_cb_array_size = data -> max_tx_mb * sizeof (struct mcux_flexcan_tx_callback );
187+ total_size = rx_bitmap_size + tx_bitmap_size + rx_cb_array_size + tx_cb_array_size ;
188+
189+ if (total_size > sizeof (data -> heap_buffer )) {
190+ LOG_ERR ("Insufficient heap memory for CAN buffers. Required: %zu, Available: %zu" ,
191+ total_size , sizeof (data -> heap_buffer ));
192+ return - ENOMEM ;
193+ }
194+ else {
195+ LOG_DBG ("Total memory size to allocate: %zu bytes" , total_size );
196+ }
197+
198+ data -> rx_allocs = NULL ;
199+ data -> tx_allocs = NULL ;
200+ data -> rx_cbs = NULL ;
201+ data -> tx_cbs = NULL ;
202+
203+ /* Dynamic allocate memory for TX RX data structures using heap */
204+ k_heap_init (& data -> instance_heap , data -> heap_buffer , sizeof (data -> heap_buffer ));
205+
206+ data -> rx_allocs = k_heap_alloc (& data -> instance_heap , rx_bitmap_size , K_NO_WAIT );
207+ data -> tx_allocs = k_heap_alloc (& data -> instance_heap , tx_bitmap_size , K_NO_WAIT );
208+ data -> rx_cbs = k_heap_alloc (& data -> instance_heap , rx_cb_array_size , K_NO_WAIT );
209+ data -> tx_cbs = k_heap_alloc (& data -> instance_heap , tx_cb_array_size , K_NO_WAIT );
210+
211+ if (!data -> rx_allocs || !data -> tx_allocs || !data -> rx_cbs || !data -> tx_cbs ) {
212+ LOG_ERR ("Failed to allocate memory for CAN buffers" );
213+ goto cleanup ;
214+ }
215+
216+ memset (data -> rx_allocs , 0 , rx_bitmap_size );
217+ memset (data -> tx_allocs , 0 , tx_bitmap_size );
218+ memset (data -> rx_cbs , 0 , rx_cb_array_size );
219+ memset (data -> tx_cbs , 0 , tx_cb_array_size );
220+
221+ return 0 ;
222+
223+ cleanup :
224+ if (data -> tx_cbs ) {
225+ k_heap_free (& data -> instance_heap , data -> tx_cbs );
226+ data -> tx_cbs = NULL ;
227+ }
228+ if (data -> rx_cbs ) {
229+ k_heap_free (& data -> instance_heap , data -> rx_cbs );
230+ data -> rx_cbs = NULL ;
231+ }
232+ if (data -> tx_allocs ) {
233+ k_heap_free (& data -> instance_heap , data -> tx_allocs );
234+ data -> tx_allocs = NULL ;
235+ }
236+ if (data -> rx_allocs ) {
237+ k_heap_free (& data -> instance_heap , data -> rx_allocs );
238+ data -> rx_allocs = NULL ;
239+ }
240+ return - ENOMEM ;
241+ }
242+
136243static int mcux_flexcan_get_core_clock (const struct device * dev , uint32_t * rate )
137244{
138245 const struct mcux_flexcan_config * config = dev -> config ;
@@ -209,7 +316,7 @@ static status_t mcux_flexcan_mb_start(const struct device *dev, int alloc)
209316 flexcan_mb_transfer_t xfer ;
210317 status_t status ;
211318
212- __ASSERT_NO_MSG (alloc >= 0 && alloc < ARRAY_SIZE ( data -> rx_cbs ) );
319+ __ASSERT_NO_MSG (alloc >= 0 && alloc < data -> max_rx_mb );
213320
214321 xfer .mbIdx = ALLOC_IDX_TO_RXMB_IDX (alloc );
215322
@@ -237,7 +344,7 @@ static void mcux_flexcan_mb_stop(const struct device *dev, int alloc)
237344 struct mcux_flexcan_data * data = dev -> data ;
238345 CAN_Type * base = get_base (dev );
239346
240- __ASSERT_NO_MSG (alloc >= 0 && alloc < ARRAY_SIZE ( data -> rx_cbs ) );
347+ __ASSERT_NO_MSG (alloc >= 0 && alloc < data -> max_rx_mb );
241348
242349#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD
243350 if ((data -> common .mode & CAN_MODE_FD ) != 0U ) {
@@ -288,7 +395,7 @@ static int mcux_flexcan_start(const struct device *dev)
288395 /* Re-add all RX filters using current mode */
289396 k_mutex_lock (& data -> rx_mutex , K_FOREVER );
290397
291- for (alloc = RX_START_IDX ; alloc < MCUX_FLEXCAN_MAX_RX ; alloc ++ ) {
398+ for (alloc = RX_START_IDX ; alloc < data -> max_rx_mb ; alloc ++ ) {
292399 if (atomic_test_bit (data -> rx_allocs , alloc )) {
293400 status = mcux_flexcan_mb_start (dev , alloc );
294401 if (status != kStatus_Success ) {
@@ -351,7 +458,7 @@ static int mcux_flexcan_stop(const struct device *dev)
351458 data -> common .started = false;
352459
353460 /* Abort any pending TX frames before entering freeze mode */
354- for (alloc = 0 ; alloc < MCUX_FLEXCAN_MAX_TX ; alloc ++ ) {
461+ for (alloc = 0 ; alloc < data -> max_tx_mb ; alloc ++ ) {
355462 function = data -> tx_cbs [alloc ].function ;
356463 arg = data -> tx_cbs [alloc ].arg ;
357464
@@ -382,7 +489,7 @@ static int mcux_flexcan_stop(const struct device *dev)
382489 */
383490 k_mutex_lock (& data -> rx_mutex , K_FOREVER );
384491
385- for (alloc = RX_START_IDX ; alloc < MCUX_FLEXCAN_MAX_RX ; alloc ++ ) {
492+ for (alloc = RX_START_IDX ; alloc < data -> max_rx_mb ; alloc ++ ) {
386493 if (atomic_test_bit (data -> rx_allocs , alloc )) {
387494 mcux_flexcan_mb_stop (dev , alloc );
388495 }
@@ -744,7 +851,7 @@ static int mcux_flexcan_send(const struct device *dev,
744851 return - EAGAIN ;
745852 }
746853
747- for (alloc = 0 ; alloc < MCUX_FLEXCAN_MAX_TX ; alloc ++ ) {
854+ for (alloc = 0 ; alloc < data -> max_tx_mb ; alloc ++ ) {
748855 if (!atomic_test_and_set_bit (data -> tx_allocs , alloc )) {
749856 break ;
750857 }
@@ -817,7 +924,7 @@ static int mcux_flexcan_add_rx_filter(const struct device *dev,
817924 k_mutex_lock (& data -> rx_mutex , K_FOREVER );
818925
819926 /* Find and allocate RX message buffer */
820- for (i = RX_START_IDX ; i < MCUX_FLEXCAN_MAX_RX ; i ++ ) {
927+ for (i = RX_START_IDX ; i < data -> max_rx_mb ; i ++ ) {
821928 if (!atomic_test_and_set_bit (data -> rx_allocs , i )) {
822929 alloc = i ;
823930 break ;
@@ -920,7 +1027,7 @@ static void mcux_flexcan_remove_rx_filter(const struct device *dev, int filter_i
9201027{
9211028 struct mcux_flexcan_data * data = dev -> data ;
9221029
923- if (filter_id < 0 || filter_id >= MCUX_FLEXCAN_MAX_RX ) {
1030+ if (filter_id < 0 || filter_id >= data -> max_rx_mb ) {
9241031 LOG_ERR ("filter ID %d out of bounds" , filter_id );
9251032 return ;
9261033 }
@@ -996,7 +1103,7 @@ static inline void mcux_flexcan_transfer_error_status(const struct device *dev,
9961103
9971104 if (state == CAN_STATE_BUS_OFF ) {
9981105 /* Abort any pending TX frames in case of bus-off */
999- for (alloc = 0 ; alloc < MCUX_FLEXCAN_MAX_TX ; alloc ++ ) {
1106+ for (alloc = 0 ; alloc < data -> max_tx_mb ; alloc ++ ) {
10001107 /* Copy callback function and argument before clearing bit */
10011108 function = data -> tx_cbs [alloc ].function ;
10021109 arg = data -> tx_cbs [alloc ].arg ;
@@ -1159,6 +1266,7 @@ static int mcux_flexcan_init(const struct device *dev)
11591266 struct mcux_flexcan_data * data = dev -> data ;
11601267 CAN_Type * base ;
11611268 flexcan_config_t flexcan_config ;
1269+ uint32_t max_mb , max_rx , max_tx ;
11621270 uint32_t clock_freq ;
11631271 int err ;
11641272
@@ -1176,10 +1284,31 @@ static int mcux_flexcan_init(const struct device *dev)
11761284
11771285 DEVICE_MMIO_NAMED_MAP (dev , flexcan_mmio , K_MEM_CACHE_NONE | K_MEM_DIRECT_MAP );
11781286
1287+ err = mcux_flexcan_get_mb_config (dev , & max_mb , & max_rx , & max_tx );
1288+ if (err != 0 ) {
1289+ return err ;
1290+ }
1291+
1292+ if (max_mb == 0 || max_rx == 0 || max_tx == 0 ) {
1293+ LOG_ERR ("Invalid message buffer configuration. max_mb: %d, rx_mb: %d, tx_mb: %d" ,
1294+ max_mb , max_rx , max_tx );
1295+ return - EINVAL ;
1296+ }
1297+ else {
1298+ LOG_DBG ("max_mb: %d, rx_mb: %d, tx_mb: %d" , max_mb , max_rx , max_tx );
1299+ }
1300+
1301+ data -> max_rx_mb = max_rx ;
1302+ data -> max_tx_mb = max_tx ;
1303+
1304+ err = mcux_flexcan_allocate_memory (dev );
1305+ if (err != 0 ) {
1306+ return err ;
1307+ }
1308+
11791309 k_mutex_init (& data -> rx_mutex );
11801310 k_mutex_init (& data -> tx_mutex );
1181- k_sem_init (& data -> tx_allocs_sem , MCUX_FLEXCAN_MAX_TX ,
1182- MCUX_FLEXCAN_MAX_TX );
1311+ k_sem_init (& data -> tx_allocs_sem , max_tx , max_tx );
11831312
11841313 err = can_calc_timing (dev , & data -> timing , config -> common .bitrate ,
11851314 config -> common .sample_point );
@@ -1235,7 +1364,7 @@ static int mcux_flexcan_init(const struct device *dev)
12351364 data -> dev = dev ;
12361365
12371366 FLEXCAN_GetDefaultConfig (& flexcan_config );
1238- flexcan_config .maxMbNum = MCUX_FLEXCAN_MAX_MB ;
1367+ flexcan_config .maxMbNum = max_mb ;
12391368 flexcan_config .clkSrc = config -> clk_source ;
12401369 flexcan_config .baudRate = clock_freq /
12411370 (1U + data -> timing .prop_seg + data -> timing .phase_seg1 +
@@ -1446,6 +1575,7 @@ static DEVICE_API(can, mcux_flexcan_fd_driver_api) = {
14461575 .clock_subsys = (clock_control_subsys_t) \
14471576 DT_INST_CLOCKS_CELL(id, name), \
14481577 .clk_source = DT_INST_PROP(id, clk_source), \
1578+ .max_mb = DT_INST_PROP(id, nxp_max_mb), \
14491579 IF_ENABLED(CONFIG_CAN_MCUX_FLEXCAN_FD, ( \
14501580 .flexcan_fd = DT_INST_NODE_HAS_COMPAT(id, FLEXCAN_FD_DRV_COMPAT), \
14511581 )) \
0 commit comments