drivers: can: mcp251xfd: Add can statistics support

Adds support for tracking CAN bus errors when CONFIG_CAN_STATS=y

Signed-off-by: Andriy Gelman <andriy.gelman@gmail.com>
This commit is contained in:
Andriy Gelman 2024-03-18 14:57:07 -04:00 committed by Johan Hedberg
parent 20b2c98add
commit 8372df0a48

View File

@ -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);