Skip to content

Commit 205defb

Browse files
drivers: can: mcux: flexcan: move to per-instance MB configuration
This change refactors the FlexCAN driver to use per-instance message buffer configuration instead of global Kconfig options. The driver now calculates message buffer allocation at compile time based on device tree properties for each FlexCAN instance. Key changes: - Remove global CAN_MAX_MB Kconfig option and associated range constraint - Add max_mb, rx_mb, and tx_mb fields to mcux_flexcan_config structure - Move callback arrays and atomic allocation bitmaps from static global arrays to per-instance static arrays generated by macros - Update data structure to use pointers to per-instance arrays instead of fixed-size embedded arrays - Add compile-time validation to ensure sufficient message buffers are available for required RX filters This approach allows different FlexCAN instances to have different message buffer configurations based on their hardware capabilities and device tree settings, improving memory efficiency and flexibility. The change maintains backward compatibility while enabling better resource utilization across different SoC variants. Fixes #92798 Signed-off-by: William Tang <william.tang@nxp.com>
1 parent 45b9fcd commit 205defb

File tree

3 files changed

+74
-63
lines changed

3 files changed

+74
-63
lines changed

boards/nxp/mr_canhubk3/doc/index.rst

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -143,12 +143,9 @@ flexcan5 | PTC11 | PTC11_CAN0_RX P22/P23
143143
and support maximum 32 message buffers for concurrent active instances with 8 bytes
144144
payload. We need to pay attention to configuration options:
145145

146-
1. :kconfig:option:`CONFIG_CAN_MAX_MB` must be less or equal than the
146+
1. :kconfig:option:`CONFIG_CAN_MAX_FILTER` must be less or equal than the
147147
maximum number of message buffers that is according to the table below.
148148

149-
2. :kconfig:option:`CONFIG_CAN_MAX_FILTER` must be less or equal than
150-
:kconfig:option:`CONFIG_CAN_MAX_MB`.
151-
152149
=============== ========== ================ ================
153150
Devicetree node Payload Hardware support Software support
154151
=============== ========== ================ ================

drivers/can/Kconfig.mcux

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -28,27 +28,9 @@ config CAN_MCUX_FLEXCAN_WAIT_TIMEOUT
2828
Maximum number of wait loop iterations for the MCUX FlexCAN HAL when entering/leaving
2929
freeze mode.
3030

31-
config CAN_MAX_MB
32-
int "Maximum number of message buffers for concurrent active instances"
33-
default 16
34-
depends on SOC_SERIES_S32K3 || SOC_SERIES_S32K1 || SOC_SERIES_S32ZE
35-
range 1 96 if SOC_SERIES_S32K3
36-
range 1 32 if SOC_SERIES_S32K1 && !SOC_S32K142W && !SOC_S32K144W
37-
range 1 64 if SOC_S32K142W || SOC_S32K144W
38-
range 1 128 if SOC_SERIES_S32ZE
39-
help
40-
Defines maximum number of message buffers for concurrent active instances.
41-
4231
config CAN_MAX_FILTER
4332
int "Maximum number of concurrent active RX filters"
4433
default 5
45-
range 1 15 if SOC_SERIES_KINETIS_KE1XF || SOC_SERIES_KINETIS_K6X
46-
range 1 13 if (SOC_SERIES_IMXRT10XX || SOC_SERIES_IMXRT11XX) && CAN_MCUX_FLEXCAN_FD
47-
range 1 63 if SOC_SERIES_IMXRT10XX || SOC_SERIES_IMXRT11XX
48-
range 1 96 if SOC_SERIES_S32K3
49-
range 1 32 if SOC_SERIES_S32K1 && !SOC_S32K142W && !SOC_S32K144W
50-
range 1 64 if SOC_S32K142W || SOC_S32K144W
51-
range 1 128 if SOC_SERIES_S32ZE
5234
help
5335
Defines maximum number of concurrent active RX filters
5436

drivers/can/can_mcux_flexcan.c

Lines changed: 73 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -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 - ((const struct mcux_flexcan_config *)dev->config)->rx_mb)
48+
#define ALLOC_IDX_TO_TXMB_IDX(x) (x + ((const struct mcux_flexcan_config *)dev->config)->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,9 @@ struct mcux_flexcan_config {
7965
const struct device *clock_dev;
8066
clock_control_subsys_t clock_subsys;
8167
int clk_source;
68+
uint32_t max_mb;
69+
uint32_t rx_mb;
70+
uint32_t tx_mb;
8271
#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD
8372
bool flexcan_fd;
8473
#endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */
@@ -113,16 +102,18 @@ struct mcux_flexcan_data {
113102
const struct device *dev;
114103
flexcan_handle_t handle;
115104

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];
124105
enum can_state state;
125106
struct can_timing timing;
107+
108+
atomic_t *rx_allocs;
109+
atomic_t *tx_allocs;
110+
struct mcux_flexcan_rx_callback *rx_cbs;
111+
struct mcux_flexcan_tx_callback *tx_cbs;
112+
113+
struct k_mutex rx_mutex;
114+
struct k_mutex tx_mutex;
115+
struct k_sem tx_allocs_sem;
116+
126117
#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD
127118
struct can_timing timing_data;
128119
#endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */
@@ -204,12 +195,13 @@ static int mcux_flexcan_get_capabilities(const struct device *dev, can_mode_t *c
204195

205196
static status_t mcux_flexcan_mb_start(const struct device *dev, int alloc)
206197
{
198+
__maybe_unused const struct mcux_flexcan_config *config = dev->config;
207199
struct mcux_flexcan_data *data = dev->data;
208200
CAN_Type *base = get_base(dev);
209201
flexcan_mb_transfer_t xfer;
210202
status_t status;
211203

212-
__ASSERT_NO_MSG(alloc >= 0 && alloc < ARRAY_SIZE(data->rx_cbs));
204+
__ASSERT_NO_MSG(alloc >= 0 && alloc < config->rx_mb);
213205

214206
xfer.mbIdx = ALLOC_IDX_TO_RXMB_IDX(alloc);
215207

@@ -234,10 +226,11 @@ static status_t mcux_flexcan_mb_start(const struct device *dev, int alloc)
234226

235227
static void mcux_flexcan_mb_stop(const struct device *dev, int alloc)
236228
{
229+
__maybe_unused const struct mcux_flexcan_config *config = dev->config;
237230
struct mcux_flexcan_data *data = dev->data;
238231
CAN_Type *base = get_base(dev);
239232

240-
__ASSERT_NO_MSG(alloc >= 0 && alloc < ARRAY_SIZE(data->rx_cbs));
233+
__ASSERT_NO_MSG(alloc >= 0 && alloc < config->rx_mb);
241234

242235
#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD
243236
if ((data->common.mode & CAN_MODE_FD) != 0U) {
@@ -288,7 +281,7 @@ static int mcux_flexcan_start(const struct device *dev)
288281
/* Re-add all RX filters using current mode */
289282
k_mutex_lock(&data->rx_mutex, K_FOREVER);
290283

291-
for (alloc = RX_START_IDX; alloc < MCUX_FLEXCAN_MAX_RX; alloc++) {
284+
for (alloc = RX_START_IDX; alloc < config->rx_mb; alloc++) {
292285
if (atomic_test_bit(data->rx_allocs, alloc)) {
293286
status = mcux_flexcan_mb_start(dev, alloc);
294287
if (status != kStatus_Success) {
@@ -351,7 +344,7 @@ static int mcux_flexcan_stop(const struct device *dev)
351344
data->common.started = false;
352345

353346
/* Abort any pending TX frames before entering freeze mode */
354-
for (alloc = 0; alloc < MCUX_FLEXCAN_MAX_TX; alloc++) {
347+
for (alloc = 0; alloc < config->tx_mb; alloc++) {
355348
function = data->tx_cbs[alloc].function;
356349
arg = data->tx_cbs[alloc].arg;
357350

@@ -382,7 +375,7 @@ static int mcux_flexcan_stop(const struct device *dev)
382375
*/
383376
k_mutex_lock(&data->rx_mutex, K_FOREVER);
384377

385-
for (alloc = RX_START_IDX; alloc < MCUX_FLEXCAN_MAX_RX; alloc++) {
378+
for (alloc = RX_START_IDX; alloc < config->rx_mb; alloc++) {
386379
if (atomic_test_bit(data->rx_allocs, alloc)) {
387380
mcux_flexcan_mb_stop(dev, alloc);
388381
}
@@ -744,7 +737,7 @@ static int mcux_flexcan_send(const struct device *dev,
744737
return -EAGAIN;
745738
}
746739

747-
for (alloc = 0; alloc < MCUX_FLEXCAN_MAX_TX; alloc++) {
740+
for (alloc = 0; alloc < config->tx_mb; alloc++) {
748741
if (!atomic_test_and_set_bit(data->tx_allocs, alloc)) {
749742
break;
750743
}
@@ -799,9 +792,7 @@ static int mcux_flexcan_add_rx_filter(const struct device *dev,
799792
void *user_data,
800793
const struct can_filter *filter)
801794
{
802-
#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD
803795
const struct mcux_flexcan_config *config = dev->config;
804-
#endif
805796
struct mcux_flexcan_data *data = dev->data;
806797
CAN_Type *base = get_base(dev);
807798
status_t status;
@@ -817,7 +808,7 @@ static int mcux_flexcan_add_rx_filter(const struct device *dev,
817808
k_mutex_lock(&data->rx_mutex, K_FOREVER);
818809

819810
/* Find and allocate RX message buffer */
820-
for (i = RX_START_IDX; i < MCUX_FLEXCAN_MAX_RX; i++) {
811+
for (i = RX_START_IDX; i < config->rx_mb; i++) {
821812
if (!atomic_test_and_set_bit(data->rx_allocs, i)) {
822813
alloc = i;
823814
break;
@@ -918,9 +909,10 @@ static int mcux_flexcan_recover(const struct device *dev, k_timeout_t timeout)
918909

919910
static void mcux_flexcan_remove_rx_filter(const struct device *dev, int filter_id)
920911
{
912+
const struct mcux_flexcan_config *config = dev->config;
921913
struct mcux_flexcan_data *data = dev->data;
922914

923-
if (filter_id < 0 || filter_id >= MCUX_FLEXCAN_MAX_RX) {
915+
if (filter_id < 0 || filter_id >= config->rx_mb) {
924916
LOG_ERR("filter ID %d out of bounds", filter_id);
925917
return;
926918
}
@@ -929,8 +921,6 @@ static void mcux_flexcan_remove_rx_filter(const struct device *dev, int filter_i
929921

930922
if (atomic_test_and_clear_bit(data->rx_allocs, filter_id)) {
931923
#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD
932-
const struct mcux_flexcan_config *config = dev->config;
933-
934924
/* Stop FlexCAN FD MBs unless already in stopped mode */
935925
if (!config->flexcan_fd || data->common.started) {
936926
#endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */
@@ -951,6 +941,7 @@ static void mcux_flexcan_remove_rx_filter(const struct device *dev, int filter_i
951941
static inline void mcux_flexcan_transfer_error_status(const struct device *dev,
952942
uint64_t error)
953943
{
944+
const struct mcux_flexcan_config *config = dev->config;
954945
struct mcux_flexcan_data *data = dev->data;
955946
CAN_Type *base = get_base(dev);
956947
const can_state_change_callback_t cb = data->common.state_change_cb;
@@ -996,7 +987,7 @@ static inline void mcux_flexcan_transfer_error_status(const struct device *dev,
996987

997988
if (state == CAN_STATE_BUS_OFF) {
998989
/* Abort any pending TX frames in case of bus-off */
999-
for (alloc = 0; alloc < MCUX_FLEXCAN_MAX_TX; alloc++) {
990+
for (alloc = 0; alloc < config->tx_mb; alloc++) {
1000991
/* Copy callback function and argument before clearing bit */
1001992
function = data->tx_cbs[alloc].function;
1002993
arg = data->tx_cbs[alloc].arg;
@@ -1176,10 +1167,12 @@ static int mcux_flexcan_init(const struct device *dev)
11761167

11771168
DEVICE_MMIO_NAMED_MAP(dev, flexcan_mmio, K_MEM_CACHE_NONE | K_MEM_DIRECT_MAP);
11781169

1170+
LOG_DBG("Message Buffers: %d, RX MB: %d, TX MB: %d",
1171+
config->max_mb, config->rx_mb, config->tx_mb);
1172+
11791173
k_mutex_init(&data->rx_mutex);
11801174
k_mutex_init(&data->tx_mutex);
1181-
k_sem_init(&data->tx_allocs_sem, MCUX_FLEXCAN_MAX_TX,
1182-
MCUX_FLEXCAN_MAX_TX);
1175+
k_sem_init(&data->tx_allocs_sem, config->tx_mb, config->tx_mb);
11831176

11841177
err = can_calc_timing(dev, &data->timing, config->common.bitrate,
11851178
config->common.sample_point);
@@ -1235,7 +1228,7 @@ static int mcux_flexcan_init(const struct device *dev)
12351228
data->dev = dev;
12361229

12371230
FLEXCAN_GetDefaultConfig(&flexcan_config);
1238-
flexcan_config.maxMbNum = MCUX_FLEXCAN_MAX_MB;
1231+
flexcan_config.maxMbNum = config->max_mb;
12391232
flexcan_config.clkSrc = config->clk_source;
12401233
flexcan_config.baudRate = clock_freq /
12411234
(1U + data->timing.prop_seg + data->timing.phase_seg1 +
@@ -1432,20 +1425,54 @@ static DEVICE_API(can, mcux_flexcan_fd_driver_api) = {
14321425
#define FLEXCAN_DRIVER_API(id) mcux_flexcan_driver_api
14331426
#endif /* !CONFIG_CAN_MCUX_FLEXCAN_FD */
14341427

1428+
#define FLEXCAN_INST_MAX_MB(id) \
1429+
COND_CODE_1(UTIL_AND(IS_ENABLED(CONFIG_CAN_MCUX_FLEXCAN_FD), \
1430+
DT_INST_NODE_HAS_COMPAT(id, FLEXCAN_FD_DRV_COMPAT)), \
1431+
(DT_INST_PROP(id, nxp_max_mb_fd)), \
1432+
(DT_INST_PROP(id, nxp_max_mb)))
1433+
1434+
/*
1435+
* RX message buffers (filters) will take up the first N message
1436+
* buffers. The rest are available for TX use.
1437+
*/
1438+
#define FLEXCAN_INST_RX_MB(id) (CONFIG_CAN_MAX_FILTER + RX_START_IDX)
1439+
#define FLEXCAN_INST_TX_MB(id) (FLEXCAN_INST_MAX_MB(id) - FLEXCAN_INST_RX_MB(id))
1440+
1441+
#define FLEXCAN_CHECK_MAX_FILTER(id) \
1442+
BUILD_ASSERT(FLEXCAN_INST_MAX_MB(id) >= FLEXCAN_INST_RX_MB(id), \
1443+
"FlexCAN instance " STRINGIFY(id) " max-mb (" \
1444+
STRINGIFY(FLEXCAN_INST_MAX_MB(id)) \
1445+
") is too small for required RX filters (" \
1446+
STRINGIFY(FLEXCAN_INST_RX_MB(id)) ")")
1447+
14351448
#define FLEXCAN_DEVICE_INIT_MCUX(id) \
14361449
PINCTRL_DT_INST_DEFINE(id); \
1450+
FLEXCAN_CHECK_MAX_FILTER(id); \
14371451
\
14381452
static void mcux_flexcan_irq_config_##id(const struct device *dev); \
14391453
static void mcux_flexcan_irq_enable_##id(void); \
14401454
static void mcux_flexcan_irq_disable_##id(void); \
14411455
\
1456+
static struct mcux_flexcan_rx_callback flexcan_rx_cbs_##id \
1457+
[FLEXCAN_INST_RX_MB(id)] = {0}; \
1458+
\
1459+
static struct mcux_flexcan_tx_callback flexcan_tx_cbs_##id \
1460+
[FLEXCAN_INST_TX_MB(id)] = {0}; \
1461+
\
1462+
static ATOMIC_DEFINE(flexcan_rx_allocs_##id, FLEXCAN_INST_RX_MB(id)); \
1463+
\
1464+
static ATOMIC_DEFINE(flexcan_tx_allocs_##id, FLEXCAN_INST_TX_MB(id)); \
1465+
\
14421466
static const struct mcux_flexcan_config mcux_flexcan_config_##id = { \
14431467
DEVICE_MMIO_NAMED_ROM_INIT(flexcan_mmio, DT_DRV_INST(id)), \
14441468
.common = CAN_DT_DRIVER_CONFIG_INST_GET(id, 0, FLEXCAN_MAX_BITRATE(id)), \
14451469
.clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(id)), \
14461470
.clock_subsys = (clock_control_subsys_t) \
14471471
DT_INST_CLOCKS_CELL(id, name), \
14481472
.clk_source = DT_INST_PROP(id, clk_source), \
1473+
.max_mb = FLEXCAN_INST_MAX_MB(id), \
1474+
.rx_mb = FLEXCAN_INST_RX_MB(id), \
1475+
.tx_mb = FLEXCAN_INST_TX_MB(id), \
14491476
IF_ENABLED(CONFIG_CAN_MCUX_FLEXCAN_FD, ( \
14501477
.flexcan_fd = DT_INST_NODE_HAS_COMPAT(id, FLEXCAN_FD_DRV_COMPAT), \
14511478
)) \
@@ -1455,7 +1482,12 @@ static DEVICE_API(can, mcux_flexcan_fd_driver_api) = {
14551482
.pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(id), \
14561483
}; \
14571484
\
1458-
static struct mcux_flexcan_data mcux_flexcan_data_##id; \
1485+
static struct mcux_flexcan_data mcux_flexcan_data_##id = { \
1486+
.rx_cbs = flexcan_rx_cbs_##id, \
1487+
.tx_cbs = flexcan_tx_cbs_##id, \
1488+
.rx_allocs = flexcan_rx_allocs_##id, \
1489+
.tx_allocs = flexcan_tx_allocs_##id, \
1490+
}; \
14591491
\
14601492
CAN_DEVICE_DT_INST_DEFINE(id, mcux_flexcan_init, \
14611493
NULL, &mcux_flexcan_data_##id, \

0 commit comments

Comments
 (0)