Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[backport v3.5-branch] drivers: can: mcan: fix handling of bus-off status events #69427

Merged
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
53 changes: 48 additions & 5 deletions drivers/can/can_mcan.c
Original file line number Diff line number Diff line change
Expand Up @@ -426,16 +426,59 @@ int can_mcan_set_mode(const struct device *dev, can_mode_t mode)

static void can_mcan_state_change_handler(const struct device *dev)
{
const struct can_mcan_config *config = dev->config;
struct can_mcan_data *data = dev->data;
const can_state_change_callback_t cb = data->state_change_cb;
void *cb_data = data->state_change_cb_data;
const can_state_change_callback_t state_cb = data->state_change_cb;
void *state_cb_data = data->state_change_cb_data;
const struct can_mcan_callbacks *cbs = config->callbacks;
can_tx_callback_t tx_cb;
uint32_t tx_idx;
struct can_bus_err_cnt err_cnt;
enum can_state state;
uint32_t cccr;
int err;

(void)can_mcan_get_state(dev, &state, &err_cnt);

if (cb != NULL) {
cb(dev, state, err_cnt, cb_data);
if (state_cb != NULL) {
state_cb(dev, state, err_cnt, state_cb_data);
}

if (state == CAN_STATE_BUS_OFF) {
/* Request all TX buffers to be cancelled */
err = can_mcan_write_reg(dev, CAN_MCAN_TXBCR, CAN_MCAN_TXBCR_CR);
if (err != 0) {
return;
}

/* Call all TX queue callbacks with -ENETUNREACH */
for (tx_idx = 0U; tx_idx < cbs->num_tx; tx_idx++) {
tx_cb = cbs->tx[tx_idx].function;

if (tx_cb != NULL) {
cbs->tx[tx_idx].function = NULL;
tx_cb(dev, -ENETUNREACH, cbs->tx[tx_idx].user_data);
k_sem_give(&data->tx_sem);
}
}

if (IS_ENABLED(CONFIG_CAN_AUTO_BUS_OFF_RECOVERY)) {
/*
* Request leaving init mode, but do not take the lock (as we are in ISR
* context), nor wait for the result.
*/
err = can_mcan_read_reg(dev, CAN_MCAN_CCCR, &cccr);
if (err != 0) {
return;
}

cccr &= ~CAN_MCAN_CCCR_INIT;

err = can_mcan_write_reg(dev, CAN_MCAN_CCCR, cccr);
if (err != 0) {
return;
}
}
}
}

Expand Down Expand Up @@ -1532,7 +1575,7 @@ int can_mcan_init(const struct device *dev)
return err;
}

/* Interrupt on every TX fifo element*/
/* Interrupt on every TX buffer transmission event */
reg = CAN_MCAN_TXBTIE_TIE;
err = can_mcan_write_reg(dev, CAN_MCAN_TXBTIE, reg);
if (err != 0) {
Expand Down
Loading