Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions boards/nxp/mr_canhubk3/doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -143,12 +143,9 @@ flexcan5 | PTC11 | PTC11_CAN0_RX P22/P23
and support maximum 32 message buffers for concurrent active instances with 8 bytes
payload. We need to pay attention to configuration options:

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

2. :kconfig:option:`CONFIG_CAN_MAX_FILTER` must be less or equal than
:kconfig:option:`CONFIG_CAN_MAX_MB`.

=============== ========== ================ ================
Devicetree node Payload Hardware support Software support
=============== ========== ================ ================
Expand Down
18 changes: 0 additions & 18 deletions drivers/can/Kconfig.mcux
Original file line number Diff line number Diff line change
Expand Up @@ -28,27 +28,9 @@ config CAN_MCUX_FLEXCAN_WAIT_TIMEOUT
Maximum number of wait loop iterations for the MCUX FlexCAN HAL when entering/leaving
freeze mode.

config CAN_MAX_MB
int "Maximum number of message buffers for concurrent active instances"
default 16
depends on SOC_SERIES_S32K3 || SOC_SERIES_S32K1 || SOC_SERIES_S32ZE
range 1 96 if SOC_SERIES_S32K3
range 1 32 if SOC_SERIES_S32K1 && !SOC_S32K142W && !SOC_S32K144W
range 1 64 if SOC_S32K142W || SOC_S32K144W
range 1 128 if SOC_SERIES_S32ZE
help
Defines maximum number of message buffers for concurrent active instances.

config CAN_MAX_FILTER
int "Maximum number of concurrent active RX filters"
default 5
range 1 15 if SOC_SERIES_KINETIS_KE1XF || SOC_SERIES_KINETIS_K6X
range 1 13 if (SOC_SERIES_IMXRT10XX || SOC_SERIES_IMXRT11XX) && CAN_MCUX_FLEXCAN_FD
range 1 63 if SOC_SERIES_IMXRT10XX || SOC_SERIES_IMXRT11XX
range 1 96 if SOC_SERIES_S32K3
range 1 32 if SOC_SERIES_S32K1 && !SOC_S32K142W && !SOC_S32K144W
range 1 64 if SOC_S32K142W || SOC_S32K144W
range 1 128 if SOC_SERIES_S32ZE
help
Defines maximum number of concurrent active RX filters

Expand Down
116 changes: 75 additions & 41 deletions drivers/can/can_mcux_flexcan.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,6 @@ LOG_MODULE_REGISTER(can_mcux_flexcan, CONFIG_CAN_LOG_LEVEL);
#define RX_START_IDX 0
#endif

/* The maximum number of message buffers for concurrent active instances */
#ifdef CONFIG_CAN_MAX_MB
#define MCUX_FLEXCAN_MAX_MB CONFIG_CAN_MAX_MB
#else
#define MCUX_FLEXCAN_MAX_MB FSL_FEATURE_FLEXCAN_HAS_MESSAGE_BUFFER_MAX_NUMBERn(0)
#endif

/*
* RX message buffers (filters) will take up the first N message
* buffers. The rest are available for TX use.
*/
#define MCUX_FLEXCAN_MAX_RX (CONFIG_CAN_MAX_FILTER + RX_START_IDX)
#define MCUX_FLEXCAN_MAX_TX (MCUX_FLEXCAN_MAX_MB - MCUX_FLEXCAN_MAX_RX)

/*
* Convert from RX message buffer index to allocated filter ID and
* vice versa.
Expand All @@ -58,8 +44,8 @@ LOG_MODULE_REGISTER(can_mcux_flexcan, CONFIG_CAN_LOG_LEVEL);
* Convert from TX message buffer index to allocated TX ID and vice
* versa.
*/
#define TX_MBIDX_TO_ALLOC_IDX(x) (x - MCUX_FLEXCAN_MAX_RX)
#define ALLOC_IDX_TO_TXMB_IDX(x) (x + MCUX_FLEXCAN_MAX_RX)
#define TX_MBIDX_TO_ALLOC_IDX(x) (x - ((const struct mcux_flexcan_config *)dev->config)->rx_mb)
#define ALLOC_IDX_TO_TXMB_IDX(x) (x + ((const struct mcux_flexcan_config *)dev->config)->rx_mb)

/* Convert from back from FLEXCAN IDs to Zephyr CAN IDs. */
#define FLEXCAN_ID_TO_CAN_ID_STD(id) \
Expand All @@ -79,6 +65,9 @@ struct mcux_flexcan_config {
const struct device *clock_dev;
clock_control_subsys_t clock_subsys;
int clk_source;
uint32_t max_mb;
uint32_t rx_mb;
uint32_t tx_mb;
#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD
bool flexcan_fd;
#endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */
Expand Down Expand Up @@ -113,16 +102,18 @@ struct mcux_flexcan_data {
const struct device *dev;
flexcan_handle_t handle;

ATOMIC_DEFINE(rx_allocs, MCUX_FLEXCAN_MAX_RX);
struct k_mutex rx_mutex;
struct mcux_flexcan_rx_callback rx_cbs[MCUX_FLEXCAN_MAX_RX];

ATOMIC_DEFINE(tx_allocs, MCUX_FLEXCAN_MAX_TX);
struct k_sem tx_allocs_sem;
struct k_mutex tx_mutex;
struct mcux_flexcan_tx_callback tx_cbs[MCUX_FLEXCAN_MAX_TX];
enum can_state state;
struct can_timing timing;

atomic_t *rx_allocs;
atomic_t *tx_allocs;
struct mcux_flexcan_rx_callback *rx_cbs;
struct mcux_flexcan_tx_callback *tx_cbs;

struct k_mutex rx_mutex;
struct k_mutex tx_mutex;
struct k_sem tx_allocs_sem;

#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD
struct can_timing timing_data;
#endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */
Expand Down Expand Up @@ -204,12 +195,13 @@ static int mcux_flexcan_get_capabilities(const struct device *dev, can_mode_t *c

static status_t mcux_flexcan_mb_start(const struct device *dev, int alloc)
{
__maybe_unused const struct mcux_flexcan_config *config = dev->config;
struct mcux_flexcan_data *data = dev->data;
CAN_Type *base = get_base(dev);
flexcan_mb_transfer_t xfer;
status_t status;

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

xfer.mbIdx = ALLOC_IDX_TO_RXMB_IDX(alloc);

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

static void mcux_flexcan_mb_stop(const struct device *dev, int alloc)
{
__maybe_unused const struct mcux_flexcan_config *config = dev->config;
struct mcux_flexcan_data *data = dev->data;
CAN_Type *base = get_base(dev);

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

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

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

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

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

for (alloc = RX_START_IDX; alloc < MCUX_FLEXCAN_MAX_RX; alloc++) {
for (alloc = RX_START_IDX; alloc < config->rx_mb; alloc++) {
if (atomic_test_bit(data->rx_allocs, alloc)) {
mcux_flexcan_mb_stop(dev, alloc);
}
Expand Down Expand Up @@ -744,7 +737,7 @@ static int mcux_flexcan_send(const struct device *dev,
return -EAGAIN;
}

for (alloc = 0; alloc < MCUX_FLEXCAN_MAX_TX; alloc++) {
for (alloc = 0; alloc < config->tx_mb; alloc++) {
if (!atomic_test_and_set_bit(data->tx_allocs, alloc)) {
break;
}
Expand Down Expand Up @@ -799,9 +792,7 @@ static int mcux_flexcan_add_rx_filter(const struct device *dev,
void *user_data,
const struct can_filter *filter)
{
#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD
const struct mcux_flexcan_config *config = dev->config;
#endif
struct mcux_flexcan_data *data = dev->data;
CAN_Type *base = get_base(dev);
status_t status;
Expand All @@ -817,7 +808,7 @@ static int mcux_flexcan_add_rx_filter(const struct device *dev,
k_mutex_lock(&data->rx_mutex, K_FOREVER);

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

static void mcux_flexcan_remove_rx_filter(const struct device *dev, int filter_id)
{
const struct mcux_flexcan_config *config = dev->config;
struct mcux_flexcan_data *data = dev->data;

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

if (atomic_test_and_clear_bit(data->rx_allocs, filter_id)) {
#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD
const struct mcux_flexcan_config *config = dev->config;

/* Stop FlexCAN FD MBs unless already in stopped mode */
if (!config->flexcan_fd || data->common.started) {
#endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */
Expand All @@ -951,6 +941,7 @@ static void mcux_flexcan_remove_rx_filter(const struct device *dev, int filter_i
static inline void mcux_flexcan_transfer_error_status(const struct device *dev,
uint64_t error)
{
const struct mcux_flexcan_config *config = dev->config;
struct mcux_flexcan_data *data = dev->data;
CAN_Type *base = get_base(dev);
const can_state_change_callback_t cb = data->common.state_change_cb;
Expand Down Expand Up @@ -996,7 +987,7 @@ static inline void mcux_flexcan_transfer_error_status(const struct device *dev,

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

DEVICE_MMIO_NAMED_MAP(dev, flexcan_mmio, K_MEM_CACHE_NONE | K_MEM_DIRECT_MAP);

LOG_DBG("Message Buffers: %d, RX MB: %d, TX MB: %d",
config->max_mb, config->rx_mb, config->tx_mb);

k_mutex_init(&data->rx_mutex);
k_mutex_init(&data->tx_mutex);
k_sem_init(&data->tx_allocs_sem, MCUX_FLEXCAN_MAX_TX,
MCUX_FLEXCAN_MAX_TX);
k_sem_init(&data->tx_allocs_sem, config->tx_mb, config->tx_mb);

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

FLEXCAN_GetDefaultConfig(&flexcan_config);
flexcan_config.maxMbNum = MCUX_FLEXCAN_MAX_MB;
flexcan_config.maxMbNum = config->max_mb;
flexcan_config.clkSrc = config->clk_source;
flexcan_config.baudRate = clock_freq /
(1U + data->timing.prop_seg + data->timing.phase_seg1 +
Expand Down Expand Up @@ -1432,20 +1425,56 @@ static DEVICE_API(can, mcux_flexcan_fd_driver_api) = {
#define FLEXCAN_DRIVER_API(id) mcux_flexcan_driver_api
#endif /* !CONFIG_CAN_MCUX_FLEXCAN_FD */

#define FLEXCAN_INST_MAX_MB(id) \
COND_CODE_1(UTIL_AND(IS_ENABLED(CONFIG_CAN_MCUX_FLEXCAN_FD), \
DT_INST_NODE_HAS_COMPAT(id, FLEXCAN_FD_DRV_COMPAT)), \
(DT_INST_PROP(id, nxp_max_mb_fd)), \
(DT_INST_PROP(id, nxp_max_mb)))

/*
* RX message buffers (filters) will take up the first N message
* buffers. The rest are available for TX use.
*/
#define FLEXCAN_INST_RX_MB(id) (CONFIG_CAN_MAX_FILTER + RX_START_IDX)
#define FLEXCAN_INST_TX_MB(id) (FLEXCAN_INST_MAX_MB(id) - FLEXCAN_INST_RX_MB(id))

#define FLEXCAN_CHECK_MAX_FILTER(id) \
BUILD_ASSERT(CONFIG_CAN_MAX_FILTER > 0, \
"CONFIG_CAN_MAX_FILTER should greater than 0"); \
BUILD_ASSERT(FLEXCAN_INST_MAX_MB(id) > FLEXCAN_INST_RX_MB(id), \
"FlexCAN instance " STRINGIFY(id) " max-mb (" \
STRINGIFY(FLEXCAN_INST_MAX_MB(id)) \
") is too small for required RX filters (" \
STRINGIFY(FLEXCAN_INST_RX_MB(id)) ")")

#define FLEXCAN_DEVICE_INIT_MCUX(id) \
PINCTRL_DT_INST_DEFINE(id); \
FLEXCAN_CHECK_MAX_FILTER(id); \
\
static void mcux_flexcan_irq_config_##id(const struct device *dev); \
static void mcux_flexcan_irq_enable_##id(void); \
static void mcux_flexcan_irq_disable_##id(void); \
\
static struct mcux_flexcan_rx_callback flexcan_rx_cbs_##id \
[FLEXCAN_INST_RX_MB(id)] = {0}; \
\
static struct mcux_flexcan_tx_callback flexcan_tx_cbs_##id \
[FLEXCAN_INST_TX_MB(id)] = {0}; \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just query, do we need to consider the case that FLEXCAN_INST_RX_MB(id) or FLEXCAN_INST_TX_MB(id) is 0?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In previous, Kconfig symbol CAN_MAX_FILTER is confined to be greater than 0, but there was no constraint that MCUX_FLEXCAN_MAX_TX not be 0.
If MCUX_FLEXCAN_MAX_TX is 0, compiler will report following warning

zephyrproject/zephyr/drivers/can/can_mcux_flexcan.c:1041:32: warning: array subscript 'alloc' is outside the bounds of an interior zero-length array 'struct mcux_flexcan_tx_callback[0]' [-Wzero-length-bounds]
 1041 |         function = data->tx_cbs[alloc].function;

For safety, I think it would be better to confine FLEXCAN_INST_TX_MB(id) and FLEXCAN_INST_RX_MB(id) greater than 0.

\
static ATOMIC_DEFINE(flexcan_rx_allocs_##id, FLEXCAN_INST_RX_MB(id)); \
\
static ATOMIC_DEFINE(flexcan_tx_allocs_##id, FLEXCAN_INST_TX_MB(id)); \
\
static const struct mcux_flexcan_config mcux_flexcan_config_##id = { \
DEVICE_MMIO_NAMED_ROM_INIT(flexcan_mmio, DT_DRV_INST(id)), \
.common = CAN_DT_DRIVER_CONFIG_INST_GET(id, 0, FLEXCAN_MAX_BITRATE(id)), \
.clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(id)), \
.clock_subsys = (clock_control_subsys_t) \
DT_INST_CLOCKS_CELL(id, name), \
.clk_source = DT_INST_PROP(id, clk_source), \
.max_mb = FLEXCAN_INST_MAX_MB(id), \
.rx_mb = FLEXCAN_INST_RX_MB(id), \
.tx_mb = FLEXCAN_INST_TX_MB(id), \
IF_ENABLED(CONFIG_CAN_MCUX_FLEXCAN_FD, ( \
.flexcan_fd = DT_INST_NODE_HAS_COMPAT(id, FLEXCAN_FD_DRV_COMPAT), \
)) \
Expand All @@ -1455,7 +1484,12 @@ static DEVICE_API(can, mcux_flexcan_fd_driver_api) = {
.pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(id), \
}; \
\
static struct mcux_flexcan_data mcux_flexcan_data_##id; \
static struct mcux_flexcan_data mcux_flexcan_data_##id = { \
.rx_cbs = flexcan_rx_cbs_##id, \
.tx_cbs = flexcan_tx_cbs_##id, \
.rx_allocs = flexcan_rx_allocs_##id, \
.tx_allocs = flexcan_tx_allocs_##id, \
}; \
\
CAN_DEVICE_DT_INST_DEFINE(id, mcux_flexcan_init, \
NULL, &mcux_flexcan_data_##id, \
Expand Down
1 change: 1 addition & 0 deletions dts/arm/nxp/nxp_k66.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"rx-warning", "wake-up";
clocks = <&sim KINETIS_SIM_BUS_CLK 0x1030 4>;
clk-source = <1>;
nxp,max-mb = <16>;
status = "disabled";
};
};
Expand Down
6 changes: 5 additions & 1 deletion dts/arm/nxp/nxp_k6x.dtsi
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
/* SPDX-License-Identifier: Apache-2.0 */
/*
* SPDX-License-Identifier: Apache-2.0
* SPDX-FileCopyrightText: Copyright The Zephyr Project Contributors
*/

#include <mem.h>
#include <freq.h>
Expand Down Expand Up @@ -518,6 +521,7 @@
interrupt-names = "mb-0-15", "bus-off", "error", "tx-warning", "rx-warning", "wake-up";
clocks = <&sim KINETIS_SIM_BUS_CLK 0x103C 4>;
clk-source = <1>;
nxp,max-mb = <16>;
status = "disabled";
};

Expand Down
2 changes: 2 additions & 0 deletions dts/arm/nxp/nxp_ke1xf.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,7 @@
"mb-0-15";
clocks = <&scg KINETIS_SCG_BUS_CLK>;
clk-source = <1>;
nxp,max-mb = <16>;
status = "disabled";
};

Expand All @@ -422,6 +423,7 @@
"mb-0-15";
clocks = <&scg KINETIS_SCG_BUS_CLK>;
clk-source = <1>;
nxp,max-mb = <16>;
status = "disabled";
};

Expand Down
1 change: 1 addition & 0 deletions dts/arm/nxp/nxp_mcxa156.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,7 @@
interrupt-names = "common";
clocks = <&syscon MCUX_FLEXCAN0_CLK>;
clk-source = <0>;
nxp,max-mb = <32>;
status = "disabled";
};

Expand Down
Loading