Skip to content

Commit e7b4a13

Browse files
[nrf fromlist] drivers: can: mcan: implement CAN_MODE_ONE_SHOT
Implement CAN_MODE_ONE_SHOT (DAR mode) for can_mcan. To acheive this, can_mcan has been refactored to use the TX cancel feature to cancel ongoing TX when stopping, as TX can now be cancelled for other reasons than CAN stopping. The CAN_MODE_ONE_SHOT feature depends on CONFIG_CAN_STATS as we need to monitor PEA and PED events, as these are produced if a TX fails. The TCF event only works if a TX is cancelled explicitly using TXBCR due to a bug in the MCAN IP, so it can not be used to detect failed and thus cancelled TX in CAN_MODE_ONE_SHOT. Upstream PR #: 99055 Signed-off-by: Bjarki Arge Andreasen <[email protected]>
1 parent 5817682 commit e7b4a13

File tree

2 files changed

+132
-40
lines changed

2 files changed

+132
-40
lines changed

drivers/can/can_mcan.c

Lines changed: 131 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
LOG_MODULE_REGISTER(can_mcan, CONFIG_CAN_LOG_LEVEL);
1818

1919
#define CAN_INIT_TIMEOUT_MS 100
20+
#define TX_ABORTED_TIMEOUT_MS 100
2021

2122
int can_mcan_read_reg(const struct device *dev, uint16_t reg, uint32_t *val)
2223
{
@@ -286,6 +287,10 @@ int can_mcan_get_capabilities(const struct device *dev, can_mode_t *cap)
286287
*cap |= CAN_MODE_FD;
287288
}
288289

290+
if (IS_ENABLED(CONFIG_CAN_STATS)) {
291+
*cap |= CAN_MODE_ONE_SHOT;
292+
}
293+
289294
return 0;
290295
}
291296

@@ -328,6 +333,70 @@ int can_mcan_start(const struct device *dev)
328333
return err;
329334
}
330335

336+
static int can_mcan_check_txbcf(const struct device *dev, uint32_t psr, enum can_mcan_psr_lec lec)
337+
{
338+
const struct can_mcan_config *config = dev->config;
339+
const struct can_mcan_callbacks *cbs = config->callbacks;
340+
struct can_mcan_data *data = dev->data;
341+
uint32_t txbcfs;
342+
int err;
343+
can_tx_callback_t tx_cb;
344+
void *user_data;
345+
int tx_err;
346+
347+
err = can_mcan_read_reg(dev, CAN_MCAN_TXBCF, &txbcfs);
348+
if (err != 0) {
349+
LOG_ERR("failed to read tx cancellation finished (err %d)", err);
350+
return err;
351+
}
352+
353+
if (txbcfs == 0) {
354+
return 0;
355+
}
356+
357+
if (psr & CAN_MCAN_PSR_BO) {
358+
/* In bus-off state */
359+
tx_err = -ENETUNREACH;
360+
} else {
361+
switch (lec) {
362+
case CAN_MCAN_PSR_LEC_NO_ERROR:
363+
case CAN_MCAN_PSR_LEC_NO_CHANGE:
364+
/* Manually cancelled using TXBCR when MCAN is moved to stopped state */
365+
tx_err = -ENETDOWN;
366+
break;
367+
default:
368+
/* Bundle remaining errors as -EIO as there is no error specifically for
369+
* arbitration lost.
370+
*/
371+
tx_err = -EIO;
372+
break;
373+
}
374+
}
375+
376+
for (size_t tx_idx = 0; tx_idx < cbs->num_tx; tx_idx++) {
377+
if ((txbcfs & BIT(tx_idx)) == 0) {
378+
continue;
379+
}
380+
381+
if (cbs->tx[tx_idx].function == NULL) {
382+
continue;
383+
}
384+
385+
tx_cb = cbs->tx[tx_idx].function;
386+
user_data = cbs->tx[tx_idx].user_data;
387+
cbs->tx[tx_idx].function = NULL;
388+
LOG_DBG("tx buffer cancellation finished (idx %u)", tx_idx);
389+
k_sem_give(&data->tx_sem);
390+
tx_cb(dev, tx_err, user_data);
391+
}
392+
393+
if (k_sem_count_get(&data->tx_sem) == cbs->num_tx) {
394+
k_sem_give(&data->stopped_sem);
395+
}
396+
397+
return 0;
398+
}
399+
331400
static bool can_mcan_rx_filters_exist(const struct device *dev)
332401
{
333402
const struct can_mcan_config *config = dev->config;
@@ -352,17 +421,27 @@ static bool can_mcan_rx_filters_exist(const struct device *dev)
352421
int can_mcan_stop(const struct device *dev)
353422
{
354423
const struct can_mcan_config *config = dev->config;
355-
const struct can_mcan_callbacks *cbs = config->callbacks;
356424
struct can_mcan_data *data = dev->data;
357-
can_tx_callback_t tx_cb;
358-
uint32_t tx_idx;
359425
int err;
360426

361427
if (!data->common.started) {
362428
return -EALREADY;
363429
}
364430

365-
/* CAN transmissions are automatically stopped when entering init mode */
431+
/* Request all TX buffers to be cancelled */
432+
k_sem_reset(&data->stopped_sem);
433+
err = can_mcan_write_reg(dev, CAN_MCAN_TXBCR, CAN_MCAN_TXBCR_CR);
434+
if (err != 0) {
435+
return err;
436+
}
437+
438+
/* Wait for all TX buffers to be cancelled */
439+
err = k_sem_take(&data->stopped_sem, K_MSEC(TX_ABORTED_TIMEOUT_MS));
440+
if (err != 0) {
441+
LOG_ERR("Timed out waiting for all TX buffers to be cancelled");
442+
return err;
443+
}
444+
366445
err = can_mcan_enter_init_mode(dev, K_MSEC(CAN_INIT_TIMEOUT_MS));
367446
if (err != 0) {
368447
LOG_ERR("Failed to enter init mode");
@@ -381,16 +460,6 @@ int can_mcan_stop(const struct device *dev)
381460

382461
data->common.started = false;
383462

384-
for (tx_idx = 0U; tx_idx < cbs->num_tx; tx_idx++) {
385-
tx_cb = cbs->tx[tx_idx].function;
386-
387-
if (tx_cb != NULL) {
388-
cbs->tx[tx_idx].function = NULL;
389-
tx_cb(dev, -ENETDOWN, cbs->tx[tx_idx].user_data);
390-
k_sem_give(&data->tx_sem);
391-
}
392-
}
393-
394463
k_mutex_lock(&data->lock, K_FOREVER);
395464
if (!can_mcan_rx_filters_exist(dev)) {
396465
pm_device_busy_clear(dev);
@@ -416,6 +485,10 @@ int can_mcan_set_mode(const struct device *dev, can_mode_t mode)
416485
supported |= CAN_MODE_FD;
417486
}
418487

488+
if (IS_ENABLED(CONFIG_CAN_STATS)) {
489+
supported |= CAN_MODE_ONE_SHOT;
490+
}
491+
419492
if ((mode & ~(supported)) != 0U) {
420493
LOG_ERR("unsupported mode: 0x%08x", mode);
421494
return -ENOTSUP;
@@ -460,6 +533,13 @@ int can_mcan_set_mode(const struct device *dev, can_mode_t mode)
460533
}
461534
#endif /* CONFIG_CAN_FD_MODE */
462535

536+
if ((mode & CAN_MODE_ONE_SHOT) != 0) {
537+
/* Disable Automatic Retransmission */
538+
cccr |= CAN_MCAN_CCCR_DAR;
539+
} else {
540+
cccr &= ~CAN_MCAN_CCCR_DAR;
541+
}
542+
463543
err = can_mcan_write_reg(dev, CAN_MCAN_CCCR, cccr);
464544
if (err != 0) {
465545
goto unlock;
@@ -480,12 +560,9 @@ int can_mcan_set_mode(const struct device *dev, can_mode_t mode)
480560

481561
static void can_mcan_state_change_handler(const struct device *dev)
482562
{
483-
const struct can_mcan_config *config = dev->config;
484563
struct can_mcan_data *data = dev->data;
485564
const can_state_change_callback_t state_cb = data->common.state_change_cb;
486565
void *state_cb_data = data->common.state_change_cb_user_data;
487-
const struct can_mcan_callbacks *cbs = config->callbacks;
488-
can_tx_callback_t tx_cb;
489566
struct can_bus_err_cnt err_cnt;
490567
enum can_state state;
491568
uint32_t cccr;
@@ -507,17 +584,6 @@ static void can_mcan_state_change_handler(const struct device *dev)
507584
return;
508585
}
509586

510-
/* Call all TX queue callbacks with -ENETUNREACH */
511-
for (uint32_t tx_idx = 0U; tx_idx < cbs->num_tx; tx_idx++) {
512-
tx_cb = cbs->tx[tx_idx].function;
513-
514-
if (tx_cb != NULL) {
515-
cbs->tx[tx_idx].function = NULL;
516-
tx_cb(dev, -ENETUNREACH, cbs->tx[tx_idx].user_data);
517-
k_sem_give(&data->tx_sem);
518-
}
519-
}
520-
521587
if (!IS_ENABLED(CONFIG_CAN_MANUAL_RECOVERY_MODE) ||
522588
(data->common.mode & CAN_MODE_MANUAL_RECOVERY) == 0U) {
523589
/*
@@ -623,7 +689,7 @@ static void can_mcan_lec_update_stats(const struct device *dev, enum can_mcan_ps
623689
}
624690
#endif /* CONFIG_CAN_STATS */
625691

626-
static int can_mcan_read_psr(const struct device *dev, uint32_t *val)
692+
static int can_mcan_read_psr(const struct device *dev, uint32_t *val, enum can_mcan_psr_lec *lec)
627693
{
628694
/* Reading the lower byte of the PSR register clears the protocol last
629695
* error codes (LEC). To avoid missing errors, this function should be
@@ -636,14 +702,15 @@ static int can_mcan_read_psr(const struct device *dev, uint32_t *val)
636702
}
637703

638704
#ifdef CONFIG_CAN_STATS
639-
enum can_mcan_psr_lec lec;
705+
*lec = FIELD_GET(CAN_MCAN_PSR_LEC, *val);
640706

641-
lec = FIELD_GET(CAN_MCAN_PSR_LEC, *val);
642-
can_mcan_lec_update_stats(dev, lec);
643707
#ifdef CONFIG_CAN_FD_MODE
644-
lec = FIELD_GET(CAN_MCAN_PSR_DLEC, *val);
645-
can_mcan_lec_update_stats(dev, lec);
646-
#endif
708+
if (*lec == CAN_MCAN_PSR_LEC_NO_CHANGE) {
709+
*lec = FIELD_GET(CAN_MCAN_PSR_DLEC, *val);
710+
}
711+
#endif /* CONFIG_CAN_FD_MODE */
712+
713+
can_mcan_lec_update_stats(dev, *lec);
647714
#endif /* CONFIG_CAN_STATS */
648715

649716
return 0;
@@ -653,7 +720,8 @@ void can_mcan_line_0_isr(const struct device *dev)
653720
{
654721
const uint32_t events = CAN_MCAN_IR_BO | CAN_MCAN_IR_EP | CAN_MCAN_IR_EW |
655722
CAN_MCAN_IR_TEFN | CAN_MCAN_IR_TEFL | CAN_MCAN_IR_ARA |
656-
CAN_MCAN_IR_MRAF | CAN_MCAN_IR_PEA | CAN_MCAN_IR_PED;
723+
CAN_MCAN_IR_MRAF | CAN_MCAN_IR_PEA | CAN_MCAN_IR_PED |
724+
CAN_MCAN_IR_TCF;
657725
struct can_mcan_data *data = dev->data;
658726
uint32_t ir;
659727
int err;
@@ -694,11 +762,22 @@ void can_mcan_line_0_isr(const struct device *dev)
694762
#ifdef CONFIG_CAN_STATS
695763
if ((ir & (CAN_MCAN_IR_PEA | CAN_MCAN_IR_PED)) != 0U) {
696764
uint32_t reg;
765+
enum can_mcan_psr_lec lec;
766+
697767
/* This function automatically updates protocol error stats */
698-
can_mcan_read_psr(dev, &reg);
768+
can_mcan_read_psr(dev, &reg, &lec);
769+
770+
/* TCF will not be set if TX failed with DAR mode enabled, but
771+
* PEA or PED will be set, so check if TX was set.
772+
*/
773+
can_mcan_check_txbcf(dev, reg, lec);
699774
}
700775
#endif
701776

777+
if ((ir & CAN_MCAN_IR_TCF) != 0U) {
778+
can_mcan_check_txbcf(dev, 0, CAN_MCAN_PSR_LEC_NO_ERROR);
779+
}
780+
702781
err = can_mcan_read_reg(dev, CAN_MCAN_IR, &ir);
703782
if (err != 0) {
704783
return;
@@ -878,10 +957,11 @@ int can_mcan_get_state(const struct device *dev, enum can_state *state,
878957
{
879958
struct can_mcan_data *data = dev->data;
880959
uint32_t reg;
960+
enum can_mcan_psr_lec lec;
881961
int err;
882962

883963
if (state != NULL) {
884-
err = can_mcan_read_psr(dev, &reg);
964+
err = can_mcan_read_psr(dev, &reg, &lec);
885965
if (err != 0) {
886966
return err;
887967
}
@@ -952,6 +1032,7 @@ int can_mcan_send(const struct device *dev, const struct can_frame *frame, k_tim
9521032
};
9531033
uint32_t put_idx = -1;
9541034
uint32_t reg;
1035+
enum can_mcan_psr_lec lec;
9551036
int err;
9561037

9571038
LOG_DBG("Sending %zu bytes. Id: 0x%x, ID type: %s %s %s %s", data_length, frame->id,
@@ -1001,7 +1082,7 @@ int can_mcan_send(const struct device *dev, const struct can_frame *frame, k_tim
10011082
return -ENETDOWN;
10021083
}
10031084

1004-
err = can_mcan_read_psr(dev, &reg);
1085+
err = can_mcan_read_psr(dev, &reg, &lec);
10051086
if (err != 0) {
10061087
return err;
10071088
}
@@ -1424,6 +1505,7 @@ int can_mcan_init(const struct device *dev)
14241505
k_mutex_init(&data->lock);
14251506
k_mutex_init(&data->tx_mtx);
14261507
k_sem_init(&data->tx_sem, cbs->num_tx, cbs->num_tx);
1508+
k_sem_init(&data->stopped_sem, 0, 1);
14271509

14281510
if (config->common.phy != NULL && !device_is_ready(config->common.phy)) {
14291511
LOG_ERR("CAN transceiver not ready");
@@ -1533,7 +1615,7 @@ int can_mcan_init(const struct device *dev)
15331615

15341616
reg = CAN_MCAN_IE_BOE | CAN_MCAN_IE_EWE | CAN_MCAN_IE_EPE | CAN_MCAN_IE_MRAFE |
15351617
CAN_MCAN_IE_TEFLE | CAN_MCAN_IE_TEFNE | CAN_MCAN_IE_RF0NE | CAN_MCAN_IE_RF1NE |
1536-
CAN_MCAN_IE_RF0LE | CAN_MCAN_IE_RF1LE;
1618+
CAN_MCAN_IE_RF0LE | CAN_MCAN_IE_RF1LE | CAN_MCAN_IE_TCFE;
15371619
#ifdef CONFIG_CAN_STATS
15381620
/* These ISRs are only enabled/used for statistics, they are otherwise
15391621
* disabled as they may produce a significant amount of frequent ISRs.
@@ -1565,5 +1647,14 @@ int can_mcan_init(const struct device *dev)
15651647
return err;
15661648
}
15671649

1650+
/*
1651+
* Interrupt on every TX buffer cancellation finished event.
1652+
*/
1653+
reg = CAN_MCAN_TXBCIE_CFIE;
1654+
err = can_mcan_write_reg(dev, CAN_MCAN_TXBCIE, reg);
1655+
if (err != 0) {
1656+
return err;
1657+
}
1658+
15681659
return can_mcan_clear_mram(dev, 0, config->mram_size);
15691660
}

include/zephyr/drivers/can/can_mcan.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1065,6 +1065,7 @@ struct can_mcan_data {
10651065
struct k_mutex lock;
10661066
struct k_sem tx_sem;
10671067
struct k_mutex tx_mtx;
1068+
struct k_sem stopped_sem;
10681069
void *custom;
10691070
} __aligned(4);
10701071

0 commit comments

Comments
 (0)