diff --git a/drivers/can/can_mcp251xfd.c b/drivers/can/can_mcp251xfd.c index 24f66f4eea63f2..d11f64d6dbb83d 100644 --- a/drivers/can/can_mcp251xfd.c +++ b/drivers/can/can_mcp251xfd.c @@ -958,6 +958,7 @@ static int mcp251xfd_handle_ivmif(const struct device *dev) uint32_t *reg; struct mcp251xfd_data *dev_data = dev->data; int ret; + uint32_t tmp; k_mutex_lock(&dev_data->mutex, K_FOREVER); @@ -967,9 +968,9 @@ static int mcp251xfd_handle_ivmif(const struct device *dev) goto done; } - *reg = sys_le32_to_cpu(*reg); + tmp = sys_le32_to_cpu(*reg); - if ((*reg & MCP251XFD_REG_BDIAG1_TXBOERR) != 0) { + if ((tmp & MCP251XFD_REG_BDIAG1_TXBOERR) != 0) { LOG_INF("ivmif bus-off error"); mcp251xfd_reset_tx_fifos(dev, -ENETDOWN); } @@ -978,12 +979,65 @@ static int mcp251xfd_handle_ivmif(const struct device *dev) reg = mcp251xfd_get_spi_buf_ptr(dev); reg[0] = 0; ret = mcp251xfd_write(dev, MCP251XFD_REG_BDIAG1, MCP251XFD_REG_SIZE); + if (ret < 0) { + goto done; + } + + /* There's no flag for DACKERR */ + if ((tmp & MCP251XFD_REG_BDIAG1_NACKERR) != 0) { + CAN_STATS_ACK_ERROR_INC(dev); + } + + if ((tmp & (MCP251XFD_REG_BDIAG1_NBIT0ERR | MCP251XFD_REG_BDIAG1_DBIT0ERR)) != 0) { + CAN_STATS_BIT0_ERROR_INC(dev); + } + + if ((tmp & (MCP251XFD_REG_BDIAG1_NBIT1ERR | MCP251XFD_REG_BDIAG1_DBIT1ERR)) != 0) { + CAN_STATS_BIT1_ERROR_INC(dev); + } + + if ((tmp & (MCP251XFD_REG_BDIAG1_NCRCERR | MCP251XFD_REG_BDIAG1_DCRCERR)) != 0) { + CAN_STATS_CRC_ERROR_INC(dev); + } + + if ((tmp & (MCP251XFD_REG_BDIAG1_NFORMERR | MCP251XFD_REG_BDIAG1_DFORMERR)) != 0) { + CAN_STATS_FORM_ERROR_INC(dev); + } + + if ((tmp & (MCP251XFD_REG_BDIAG1_NSTUFERR | MCP251XFD_REG_BDIAG1_DSTUFERR)) != 0) { + CAN_STATS_STUFF_ERROR_INC(dev); + } done: k_mutex_unlock(&dev_data->mutex); return ret; } +#if defined(CONFIG_CAN_STATS) +static int mcp251xfd_handle_rxovif(const struct device *dev) +{ + uint8_t *reg_byte; + struct mcp251xfd_data *dev_data = dev->data; + int ret; + + k_mutex_lock(&dev_data->mutex, K_FOREVER); + + reg_byte = mcp251xfd_get_spi_buf_ptr(dev); + *reg_byte = 0; + + ret = mcp251xfd_write(dev, MCP251XFD_REG_FIFOSTA(MCP251XFD_RX_FIFO_IDX), 1); + if (ret < 0) { + goto done; + } + + CAN_STATS_RX_OVERRUN_INC(dev); + +done: + k_mutex_unlock(&dev_data->mutex); + return ret; +} +#endif + static void mcp251xfd_handle_interrupts(const struct device *dev) { const struct mcp251xfd_config *dev_cfg = dev->config; @@ -1064,6 +1118,15 @@ static void mcp251xfd_handle_interrupts(const struct device *dev) } } +#if defined(CONFIG_CAN_STATS) + if ((reg_int & MCP251XFD_REG_INT_RXOVIF) != 0) { + ret = mcp251xfd_handle_rxovif(dev); + if (ret < 0) { + LOG_ERR("Error handling RXOVIF [%d]", ret); + } + } +#endif + /* Break from loop if INT pin is inactive */ consecutive_calls++; ret = gpio_pin_get_dt(&dev_cfg->int_gpio_dt); @@ -1156,6 +1219,8 @@ static int mcp251xfd_start(const struct device *dev) k_mutex_lock(&dev_data->mutex, K_FOREVER); + CAN_STATS_RESET(dev); + ret = mcp251xfd_set_mode_internal(dev, dev_data->next_mcp251xfd_mode); if (ret < 0) { LOG_ERR("Failed to set the mode [%d]", ret); @@ -1347,6 +1412,9 @@ static inline int mcp251xfd_init_int_reg(const struct device *dev) tmp = MCP251XFD_REG_INT_RXIE | MCP251XFD_REG_INT_MODIE | MCP251XFD_REG_INT_TEFIE | MCP251XFD_REG_INT_CERRIE; +#if defined(CONFIG_CAN_STATS) + tmp |= MCP251XFD_REG_INT_RXOVIE; +#endif *reg = sys_cpu_to_le32(tmp); @@ -1388,6 +1456,9 @@ static inline int mcp251xfd_init_rx_fifo(const struct device *dev) uint32_t tmp; tmp = MCP251XFD_REG_FIFOCON_TFNRFNIE | MCP251XFD_REG_FIFOCON_FRESET; +#if defined(CONFIG_CAN_STATS) + tmp |= MCP251XFD_REG_FIFOCON_RXOVIE; +#endif tmp |= FIELD_PREP(MCP251XFD_REG_FIFOCON_FSIZE_MASK, MCP251XFD_RX_FIFO_ITEMS - 1); tmp |= FIELD_PREP(MCP251XFD_REG_FIFOCON_PLSIZE_MASK, can_bytes_to_dlc(MCP251XFD_PAYLOAD_SIZE) - 8);