diff --git a/arch/arm/src/imx9/imx9_flexcan.c b/arch/arm/src/imx9/imx9_flexcan.c index 9550597b84f4e..1bdaa09fdfbdc 100644 --- a/arch/arm/src/imx9/imx9_flexcan.c +++ b/arch/arm/src/imx9/imx9_flexcan.c @@ -628,6 +628,7 @@ static int imx9_transmit(struct imx9_driver_s *priv) /* Check whether message buffer is not currently transmitting */ struct mb_s *mb = flexcan_get_mb(priv, mbi); + if (mb->cs.code != CAN_TXMB_DATAORREMOTE) { putreg32(mb_bit, priv->base + IMX9_CAN_IFLAG1_OFFSET); @@ -650,12 +651,14 @@ static int imx9_transmit(struct imx9_driver_s *priv) #ifdef CONFIG_NET_CAN_RAW_TX_DEADLINE struct timespec ts; + clock_systime_timespec(&ts); if (priv->dev.d_sndlen > priv->dev.d_len) { struct timeval *tv = (struct timeval *)(priv->dev.d_buf + priv->dev.d_len); + priv->txmb[txmb].deadline = *tv; timeout = (tv->tv_sec - ts.tv_sec)*CLK_TCK + ((tv->tv_usec - ts.tv_nsec / 1000)*CLK_TCK) / 1000000; @@ -690,9 +693,11 @@ static int imx9_transmit(struct imx9_driver_s *priv) (peak_tx_mailbox_index_ > mbi ? peak_tx_mailbox_index_ : mbi); union cs_e cs; + cs.cs = 0; cs.code = CAN_TXMB_DATAORREMOTE; struct mb_s *mb = flexcan_get_mb(priv, mbi); + mb->cs.code = CAN_TXMB_INACTIVE; if (priv->dev.d_len == sizeof(struct can_frame)) @@ -755,6 +760,7 @@ static int imx9_transmit(struct imx9_driver_s *priv) */ struct mb_s *buffer = flexcan_get_mb(priv, RXMBCOUNT); + buffer->cs.code = 0x3; buffer->cs.code = 0x3; @@ -878,11 +884,13 @@ static void imx9_receive(struct imx9_driver_s *priv, mbj = mbi = arm_lsb(f); rf = flexcan_get_mb(priv, mbi); uint32_t t = rf->cs.time_stamp; + while ((f &= ~(1 << mbj)) != 0) { mbj = arm_lsb(f); struct mb_s *rf_next = flexcan_get_mb(priv, mbj); uint16_t t_next = rf_next->cs.time_stamp; + if ((int16_t)(t - t_next) > 0) { t = t_next; @@ -897,7 +905,7 @@ static void imx9_receive(struct imx9_driver_s *priv, #ifdef CONFIG_NET_CAN_CANFD if (rf->cs.edl) /* CAN FD frame */ { - struct canfd_frame *frame = (struct canfd_frame *)priv->rxdesc_fd; + struct canfd_frame *frame = (struct canfd_frame *)priv->rxdesc_fd; if (rf->cs.ide) { @@ -938,7 +946,7 @@ static void imx9_receive(struct imx9_driver_s *priv, else /* CAN 2.0 Frame */ #endif { - struct can_frame *frame = (struct can_frame *)priv->rxdesc; + struct can_frame *frame = (struct can_frame *)priv->rxdesc; if (rf->cs.ide) { @@ -1058,6 +1066,7 @@ static void imx9_txdone(struct imx9_driver_s *priv) wd_cancel(&priv->txtimeout[txmb]); struct mb_s *mb = flexcan_get_mb(priv, mbi); + mb->cs.code = CAN_TXMB_INACTIVE; #endif } @@ -1128,6 +1137,7 @@ static void imx9_flexcan_interrupt_work(void *arg) struct imx9_driver_s *priv = (struct imx9_driver_s *)arg; uint32_t flags; + flags = getreg32(priv->base + IMX9_CAN_IFLAG1_OFFSET); flags &= IFLAG1_RX; @@ -1168,6 +1178,7 @@ static int imx9_flexcan_interrupt(int irq, void *context, if (irq == priv->config->irq) { uint32_t flags; + flags = getreg32(priv->base + IMX9_CAN_IFLAG1_OFFSET); flags &= IFLAG1_RX; @@ -1221,6 +1232,7 @@ static void imx9_txtimeout_work(void *arg) struct timespec ts; struct timeval *now = (struct timeval *)&ts; + clock_systime_timespec(&ts); now->tv_usec = ts.tv_nsec / 1000; /* timespec to timeval conversion */ @@ -1246,6 +1258,7 @@ static void imx9_txtimeout_work(void *arg) } struct mb_s *mb = flexcan_get_mb(priv, mbi + RXMBCOUNT); + mb->cs.code = CAN_TXMB_ABORT; priv->txmb[mbi].pending = TX_ABORT; } @@ -1305,6 +1318,7 @@ static void imx9_setenable(uint32_t base, uint32_t enable) static void imx9_setfreeze(uint32_t base, uint32_t freeze) { uint32_t regval; + if (freeze) { /* Enter freeze mode */ @@ -1333,6 +1347,7 @@ static uint32_t imx9_waitmcr_change(uint32_t base, uint32_t mask, { const bool state = (getreg32(base + IMX9_CAN_MCR_OFFSET) & mask) != 0; + if (state == target_state) { return true; @@ -1544,11 +1559,12 @@ static int imx9_ioctl(struct net_driver_s *dev, int cmd, switch (cmd) { -#ifdef CONFIG_NETDEV_CAN_BITRATE_IOCTL +#ifdef CONFIG_NETDEV_CAN_IOCTL case SIOCGCANBITRATE: /* Get bitrate from a CAN controller */ { struct can_ioctl_data_s *req = (struct can_ioctl_data_s *)((uintptr_t)arg); + req->arbi_bitrate = priv->arbi_timing.bitrate; req->arbi_samplep = priv->arbi_timing.samplep; if (priv->canfd_capable) @@ -1572,6 +1588,7 @@ static int imx9_ioctl(struct net_driver_s *dev, int cmd, (struct can_ioctl_data_s *)((uintptr_t)arg); struct flexcan_timeseg arbi_timing; + arbi_timing.bitrate = req->arbi_bitrate; arbi_timing.samplep = req->arbi_samplep; @@ -1585,19 +1602,19 @@ static int imx9_ioctl(struct net_driver_s *dev, int cmd, } if (priv->canfd_capable) - { - data_timing.bitrate = req->data_bitrate; - data_timing.samplep = req->data_samplep; - - if (ret == OK && imx9_bitratetotimeseg(&data_timing, 10, 1)) - { - ret = OK; - } - else - { - ret = -EINVAL; - } - } + { + data_timing.bitrate = req->data_bitrate; + data_timing.samplep = req->data_samplep; + + if (ret == OK && imx9_bitratetotimeseg(&data_timing, 10, 1)) + { + ret = OK; + } + else + { + ret = -EINVAL; + } + } if (ret == OK) { @@ -1605,9 +1622,9 @@ static int imx9_ioctl(struct net_driver_s *dev, int cmd, priv->arbi_timing = arbi_timing; if (priv->canfd_capable) - { - priv->data_timing = data_timing; - } + { + priv->data_timing = data_timing; + } } } break; @@ -1782,12 +1799,14 @@ static int imx9_initialize(struct imx9_driver_s *priv) * transmitting the package, hence we write 0x3. */ - struct mb_s *buffer = flexcan_get_mb(priv, RXMBCOUNT); - buffer->cs.code = 0x3; + struct mb_s *buffer = flexcan_get_mb(priv, RXMBCOUNT); + + buffer->cs.code = 0x3; for (i = RXMBCOUNT + 1; i < TOTALMBCOUNT; i++) { struct mb_s *rx = flexcan_get_mb(priv, i); + rx->id.w = 0x0; /* FIXME sometimes we get a hard fault here */ @@ -1803,6 +1822,7 @@ static int imx9_initialize(struct imx9_driver_s *priv) for (i = 0; i < RXMBCOUNT; i++) { struct mb_s *rx = flexcan_get_mb(priv, i); + ninfo("Set MB%" PRIi32 " to receive %p\n", i, rx); rx->cs.edl = 0x1; rx->cs.brs = 0x1; @@ -1868,6 +1888,7 @@ static void imx9_reset(struct imx9_driver_s *priv) for (i = 0; i < TOTALMBCOUNT; i++) { struct mb_s *rx = flexcan_get_mb(priv, i); + ninfo("MB %" PRIi32 " %p\n", i, rx); ninfo("MB %" PRIi32 " %p\n", i, &rx->id.w); rx->cs.cs = 0x0; @@ -1928,143 +1949,143 @@ int imx9_caninitialize(int intf) switch (intf) { #ifdef CONFIG_IMX9_FLEXCAN1 - case 1: - priv = &g_flexcan1; - memset(priv, 0, sizeof(struct imx9_driver_s)); - priv->base = IMX9_CAN1_BASE; - priv->config = &imx9_flexcan1_config; + case 1: + priv = &g_flexcan1; + memset(priv, 0, sizeof(struct imx9_driver_s)); + priv->base = IMX9_CAN1_BASE; + priv->config = &imx9_flexcan1_config; # if defined(CONFIG_NET_CAN_CANFD) - priv->canfd_capable = true; - priv->mb_address_offset = 14; + priv->canfd_capable = true; + priv->mb_address_offset = 14; #endif - /* Default bitrate configuration */ + /* Default bitrate configuration */ # if defined(CONFIG_NET_CAN_CANFD) - priv->arbi_timing.bitrate = CONFIG_FLEXCAN1_ARBI_BITRATE; - priv->arbi_timing.samplep = CONFIG_FLEXCAN1_ARBI_SAMPLEP; - priv->data_timing.bitrate = CONFIG_FLEXCAN1_DATA_BITRATE; - priv->data_timing.samplep = CONFIG_FLEXCAN1_DATA_SAMPLEP; + priv->arbi_timing.bitrate = CONFIG_FLEXCAN1_ARBI_BITRATE; + priv->arbi_timing.samplep = CONFIG_FLEXCAN1_ARBI_SAMPLEP; + priv->data_timing.bitrate = CONFIG_FLEXCAN1_DATA_BITRATE; + priv->data_timing.samplep = CONFIG_FLEXCAN1_DATA_SAMPLEP; # else - priv->arbi_timing.bitrate = CONFIG_FLEXCAN1_BITRATE; - priv->arbi_timing.samplep = CONFIG_FLEXCAN1_SAMPLEP; + priv->arbi_timing.bitrate = CONFIG_FLEXCAN1_BITRATE; + priv->arbi_timing.samplep = CONFIG_FLEXCAN1_SAMPLEP; # endif - break; + break; #endif #ifdef CONFIG_IMX9_FLEXCAN2 - case 2: - priv = &g_flexcan2; - memset(priv, 0, sizeof(struct imx9_driver_s)); - priv->base = IMX9_CAN2_BASE; - priv->config = &imx9_flexcan2_config; + case 2: + priv = &g_flexcan2; + memset(priv, 0, sizeof(struct imx9_driver_s)); + priv->base = IMX9_CAN2_BASE; + priv->config = &imx9_flexcan2_config; # if defined(CONFIG_NET_CAN_CANFD) - priv->canfd_capable = true; - priv->mb_address_offset = 14; + priv->canfd_capable = true; + priv->mb_address_offset = 14; # else - priv->canfd_capable = false; - priv->mb_address_offset = 0; + priv->canfd_capable = false; + priv->mb_address_offset = 0; # endif - /* Default bitrate configuration */ + /* Default bitrate configuration */ # if defined(CONFIG_NET_CAN_CANFD) - priv->arbi_timing.bitrate = CONFIG_FLEXCAN2_ARBI_BITRATE; - priv->arbi_timing.samplep = CONFIG_FLEXCAN2_ARBI_SAMPLEP; - priv->data_timing.bitrate = CONFIG_FLEXCAN2_DATA_BITRATE; - priv->data_timing.samplep = CONFIG_FLEXCAN2_DATA_SAMPLEP; + priv->arbi_timing.bitrate = CONFIG_FLEXCAN2_ARBI_BITRATE; + priv->arbi_timing.samplep = CONFIG_FLEXCAN2_ARBI_SAMPLEP; + priv->data_timing.bitrate = CONFIG_FLEXCAN2_DATA_BITRATE; + priv->data_timing.samplep = CONFIG_FLEXCAN2_DATA_SAMPLEP; # else - priv->arbi_timing.bitrate = CONFIG_FLEXCAN2_BITRATE; - priv->arbi_timing.samplep = CONFIG_FLEXCAN2_SAMPLEP; + priv->arbi_timing.bitrate = CONFIG_FLEXCAN2_BITRATE; + priv->arbi_timing.samplep = CONFIG_FLEXCAN2_SAMPLEP; # endif - break; + break; #endif #ifdef CONFIG_IMX9_FLEXCAN3 - case 3: - priv = &g_flexcan3; - memset(priv, 0, sizeof(struct imx9_driver_s)); - priv->base = IMX9_CAN3_BASE; - priv->config = &imx9_flexcan3_config; + case 3: + priv = &g_flexcan3; + memset(priv, 0, sizeof(struct imx9_driver_s)); + priv->base = IMX9_CAN3_BASE; + priv->config = &imx9_flexcan3_config; # ifdef CONFIG_NET_CAN_CANFD - priv->canfd_capable = true; - priv->mb_address_offset = 14; + priv->canfd_capable = true; + priv->mb_address_offset = 14; # else - priv->canfd_capable = false; - priv->mb_address_offset = 0; + priv->canfd_capable = false; + priv->mb_address_offset = 0; # endif - /* Default bitrate configuration */ + /* Default bitrate configuration */ # ifdef CONFIG_NET_CAN_CANFD - priv->arbi_timing.bitrate = CONFIG_FLEXCAN3_ARBI_BITRATE; - priv->arbi_timing.samplep = CONFIG_FLEXCAN3_ARBI_SAMPLEP; - priv->data_timing.bitrate = CONFIG_FLEXCAN3_DATA_BITRATE; - priv->data_timing.samplep = CONFIG_FLEXCAN3_DATA_SAMPLEP; + priv->arbi_timing.bitrate = CONFIG_FLEXCAN3_ARBI_BITRATE; + priv->arbi_timing.samplep = CONFIG_FLEXCAN3_ARBI_SAMPLEP; + priv->data_timing.bitrate = CONFIG_FLEXCAN3_DATA_BITRATE; + priv->data_timing.samplep = CONFIG_FLEXCAN3_DATA_SAMPLEP; # else - priv->arbi_timing.bitrate = CONFIG_FLEXCAN3_BITRATE; - priv->arbi_timing.samplep = CONFIG_FLEXCAN3_SAMPLEP; + priv->arbi_timing.bitrate = CONFIG_FLEXCAN3_BITRATE; + priv->arbi_timing.samplep = CONFIG_FLEXCAN3_SAMPLEP; # endif - break; + break; #endif #ifdef CONFIG_IMX9_FLEXCAN4 - case 4: - priv = &g_flexcan4; - memset(priv, 0, sizeof(struct imx9_driver_s)); - priv->base = IMX9_CAN4_BASE; - priv->config = &imx9_flexcan4_config; + case 4: + priv = &g_flexcan4; + memset(priv, 0, sizeof(struct imx9_driver_s)); + priv->base = IMX9_CAN4_BASE; + priv->config = &imx9_flexcan4_config; # ifdef CONFIG_NET_CAN_CANFD - priv->canfd_capable = true; - priv->mb_address_offset = 14; + priv->canfd_capable = true; + priv->mb_address_offset = 14; # else - priv->canfd_capable = false; - priv->mb_address_offset = 0; + priv->canfd_capable = false; + priv->mb_address_offset = 0; # endif - /* Default bitrate configuration */ + /* Default bitrate configuration */ # ifdef CONFIG_NET_CAN_CANFD - priv->arbi_timing.bitrate = CONFIG_FLEXCAN4_ARBI_BITRATE; - priv->arbi_timing.samplep = CONFIG_FLEXCAN4_ARBI_SAMPLEP; - priv->data_timing.bitrate = CONFIG_FLEXCAN4_DATA_BITRATE; - priv->data_timing.samplep = CONFIG_FLEXCAN4_DATA_SAMPLEP; + priv->arbi_timing.bitrate = CONFIG_FLEXCAN4_ARBI_BITRATE; + priv->arbi_timing.samplep = CONFIG_FLEXCAN4_ARBI_SAMPLEP; + priv->data_timing.bitrate = CONFIG_FLEXCAN4_DATA_BITRATE; + priv->data_timing.samplep = CONFIG_FLEXCAN4_DATA_SAMPLEP; # else - priv->arbi_timing.bitrate = CONFIG_FLEXCAN4_BITRATE; - priv->arbi_timing.samplep = CONFIG_FLEXCAN4_SAMPLEP; + priv->arbi_timing.bitrate = CONFIG_FLEXCAN4_BITRATE; + priv->arbi_timing.samplep = CONFIG_FLEXCAN4_SAMPLEP; # endif - break; + break; #endif #ifdef CONFIG_IMX9_FLEXCAN5 - case 5: - priv = &g_flexcan5; - memset(priv, 0, sizeof(struct imx9_driver_s)); - priv->base = IMX9_CAN5_BASE; - priv->config = &imx9_flexcan5_config; + case 5: + priv = &g_flexcan5; + memset(priv, 0, sizeof(struct imx9_driver_s)); + priv->base = IMX9_CAN5_BASE; + priv->config = &imx9_flexcan5_config; # ifdef CONFIG_NET_CAN_CANFD - priv->canfd_capable = true; - priv->mb_address_offset = 14; + priv->canfd_capable = true; + priv->mb_address_offset = 14; # else - priv->canfd_capable = false; - priv->mb_address_offset = 0; + priv->canfd_capable = false; + priv->mb_address_offset = 0; # endif - /* Default bitrate configuration */ + /* Default bitrate configuration */ # ifdef CONFIG_NET_CAN_CANFD - priv->arbi_timing.bitrate = CONFIG_FLEXCAN5_ARBI_BITRATE; - priv->arbi_timing.samplep = CONFIG_FLEXCAN5_ARBI_SAMPLEP; - priv->data_timing.bitrate = CONFIG_FLEXCAN5_DATA_BITRATE; - priv->data_timing.samplep = CONFIG_FLEXCAN5_DATA_SAMPLEP; + priv->arbi_timing.bitrate = CONFIG_FLEXCAN5_ARBI_BITRATE; + priv->arbi_timing.samplep = CONFIG_FLEXCAN5_ARBI_SAMPLEP; + priv->data_timing.bitrate = CONFIG_FLEXCAN5_DATA_BITRATE; + priv->data_timing.samplep = CONFIG_FLEXCAN5_DATA_SAMPLEP; # else - priv->arbi_timing.bitrate = CONFIG_FLEXCAN5_BITRATE; - priv->arbi_timing.samplep = CONFIG_FLEXCAN5_SAMPLEP; + priv->arbi_timing.bitrate = CONFIG_FLEXCAN5_BITRATE; + priv->arbi_timing.samplep = CONFIG_FLEXCAN5_SAMPLEP; # endif - break; + break; #endif - default: - return -ENODEV; + default: + return -ENODEV; } imx9_configure_clock(priv->config->clk_root, true); diff --git a/arch/arm/src/imxrt/hardware/imxrt_flexcan.h b/arch/arm/src/imxrt/hardware/imxrt_flexcan.h index d55ac68ee1c77..a1e7df4c594f1 100644 --- a/arch/arm/src/imxrt/hardware/imxrt_flexcan.h +++ b/arch/arm/src/imxrt/hardware/imxrt_flexcan.h @@ -435,6 +435,13 @@ #define CAN_FDCRC_FD_MBCRC(x) (((uint32_t)(((uint32_t)(x)) << CAN_FDCRC_FD_MBCRC_SHIFT)) & CAN_FDCRC_FD_MBCRC_MASK) /* Bit 31: Reserved */ +/* CAN MB RX codes */ + +#define CAN_RXMB_INACTIVE 0x0 /* MB is not active. */ +#define CAN_RXMB_FULL 0x2 /* MB is full. */ +#define CAN_RXMB_EMPTY 0x4 /* MB is empty. */ +#define CAN_RXMB_OVERRUN 0x6 /* MB is overwritten into a full buffer. */ + /* CAN MB TX codes */ #define CAN_TXMB_INACTIVE 0x8 /* MB is not active. */ #define CAN_TXMB_ABORT 0x9 /* MB is aborted. */ diff --git a/arch/arm/src/imxrt/imxrt_flexcan.c b/arch/arm/src/imxrt/imxrt_flexcan.c index 6ce94a58bb1ff..d1e8f4ef14930 100644 --- a/arch/arm/src/imxrt/imxrt_flexcan.c +++ b/arch/arm/src/imxrt/imxrt_flexcan.c @@ -298,6 +298,9 @@ struct imxrt_driver_s #ifdef CONFIG_NET_CAN_RAW_TX_DEADLINE struct txmbstats txmb[TXMBRINGSIZE]; #endif + + uint32_t bus_errors; /* ESR1 error flags observed, monotonic */ + uint32_t rx_overruns; /* RX mailbox CODE=OVERRUN count */ }; /**************************************************************************** @@ -488,7 +491,7 @@ static struct mb_s *flexcan_get_mb(struct imxrt_driver_s *priv, static void imxrt_receive(struct imxrt_driver_s *priv, uint32_t flags); -static void imxrt_txdone_work(void *arg); +static void imxrt_tx_work(void *arg); static void imxrt_txdone(struct imxrt_driver_s *priv); static int imxrt_flexcan_interrupt(int irq, void *context, @@ -497,7 +500,7 @@ static void imxrt_flexcan_interrupt_work(void *arg); /* Watchdog timer expirations */ #ifdef TX_TIMEOUT_WQ -static void imxrt_txtimeout_work(void *arg); +static void imxrt_txtimeout_abort(struct imxrt_driver_s *priv); static void imxrt_txtimeout_expiry(wdparm_t arg); #endif @@ -523,6 +526,54 @@ static void imxrt_reset(struct imxrt_driver_s *priv); * Private Functions ****************************************************************************/ +/* ESR1 error flags. Every one is set by the protocol engine on the matching + * bus error and cleared when ESR1 is read, so a read reports the error + * types seen since the previous read. Sampling them at every driver entry + * gives a monotonic error count without the ERRINT interrupt, which fires + * once per error frame and storms at bus rate on a dead bus. + */ + +#define ESR1_ERRFLAGS (CAN_ESR1_STFERR | CAN_ESR1_FRMERR | CAN_ESR1_CRCERR | \ + CAN_ESR1_ACKERR | CAN_ESR1_BIT0ERR | CAN_ESR1_BIT1ERR | \ + CAN_ESR1_STFERRFAST | CAN_ESR1_FRMERRFAST | \ + CAN_ESR1_CRCERRFAST | CAN_ESR1_BIT0ERRFAST | \ + CAN_ESR1_BIT1ERRFAST) + +/**************************************************************************** + * Function: imxrt_sample_errors + * + * Description: + * Read ESR1, clearing its error flags, and add the number of set flags + * to the bus error count. + * + * Input Parameters: + * priv - Reference to the driver state structure + * + * Returned Value: + * The ESR1 value that was read. + * + ****************************************************************************/ + +static uint32_t imxrt_sample_errors(struct imxrt_driver_s *priv) +{ + irqstate_t flags; + uint32_t esr1; + uint32_t errs; + + flags = spin_lock_irqsave(NULL); + + esr1 = getreg32(priv->base + IMXRT_CAN_ESR1_OFFSET); + + for (errs = esr1 & ESR1_ERRFLAGS; errs != 0; errs &= errs - 1) + { + priv->bus_errors++; + } + + spin_unlock_irqrestore(NULL, flags); + + return esr1; +} + /**************************************************************************** * Function: imxrt_txmb_next * @@ -895,6 +946,13 @@ static void imxrt_receive(struct imxrt_driver_s *priv, rf = flexcan_get_mb(priv, mbi); + /* CODE is in CS; read it before unlocking the mailbox via IFLAG. */ + + if (rf->cs.code == CAN_RXMB_OVERRUN) + { + priv->rx_overruns++; + } + /* Read the frame contents */ #ifdef CONFIG_NET_CAN_CANFD @@ -1067,7 +1125,7 @@ static void imxrt_txdone(struct imxrt_driver_s *priv) /* Retire the deadline with the frame. Left behind it sits in the * past forever, and the next expiry of any other mailbox's - * watchdog makes imxrt_txtimeout_work() abort whatever frame has + * watchdog makes imxrt_txtimeout_abort() abort whatever frame has * since been loaded here. */ @@ -1089,35 +1147,48 @@ static void imxrt_txdone(struct imxrt_driver_s *priv) } /**************************************************************************** - * Function: imxrt_txdone_work + * Function: imxrt_tx_work * * Description: - * An interrupt was received indicating that the last TX packet(s) is done + * Process TX completions and deadline aborts on the worker thread, then + * poll for more data. TX-complete IRQs and the deadline watchdog both + * queue this function on the same work_s; work_queue() cancels a pending + * callback when that work_s is reused, so splitting them lost whichever + * ran second (deadlines left set, TX IMASK left off, expired frames + * never aborted). * * Input Parameters: - * priv - Reference to the driver state structure + * arg - Reference to the driver state structure * * Returned Value: * None * - * Assumptions: - * Global interrupts are disabled by the watchdog logic. - * We are not in an interrupt context so that we can lock the network. - * ****************************************************************************/ -static void imxrt_txdone_work(void *arg) +static void imxrt_tx_work(void *arg) { struct imxrt_driver_s *priv = (struct imxrt_driver_s *)arg; + imxrt_sample_errors(priv); imxrt_txdone(priv); - /* There should be space for a new TX in any event. Poll the network for - * new XMIT data +#ifdef TX_TIMEOUT_WQ + imxrt_txtimeout_abort(priv); +#endif + + /* The TX IRQ masked every TX mailbox to stop the interrupt storm. + * Restore the mask so abort completions and later transmits can + * interrupt. txdone() already cleared completion flags. */ + modifyreg32(priv->base + IMXRT_CAN_IMASK1_OFFSET, 0, IFLAG1_TX); + net_lock(); - devif_poll(&priv->dev, imxrt_txpoll); + if (priv->bifup) + { + devif_poll(&priv->dev, imxrt_txpoll); + } + net_unlock(); } @@ -1150,6 +1221,8 @@ static void imxrt_flexcan_interrupt_work(void *arg) flags = getreg32(priv->base + IMXRT_CAN_IFLAG1_OFFSET); flags &= IFLAG1_RX; + imxrt_sample_errors(priv); + net_lock(); imxrt_receive(priv, flags); net_unlock(); @@ -1208,7 +1281,7 @@ static int imxrt_flexcan_interrupt(int irq, void *context, */ modifyreg32(priv->base + IMXRT_CAN_IMASK1_OFFSET, IFLAG1_TX, 0); - work_queue(CANWORK, &priv->irqwork, imxrt_txdone_work, priv, 0); + work_queue(CANWORK, &priv->irqwork, imxrt_tx_work, priv, 0); } } @@ -1216,25 +1289,24 @@ static int imxrt_flexcan_interrupt(int irq, void *context, } /**************************************************************************** - * Function: imxrt_txtimeout_work + * Function: imxrt_txtimeout_abort * * Description: - * Perform TX timeout related work from the worker thread + * Abort TX mailboxes whose deadline has passed. Called from + * imxrt_tx_work() after completions have been retired so a just-finished + * mailbox is not aborted on a stale deadline. * * Input Parameters: - * arg - The argument passed when work_queue() as called. + * priv - Reference to the driver state structure * * Returned Value: - * OK on success - * - * Assumptions: + * None * ****************************************************************************/ #ifdef TX_TIMEOUT_WQ -static void imxrt_txtimeout_work(void *arg) +static void imxrt_txtimeout_abort(struct imxrt_driver_s *priv) { - struct imxrt_driver_s *priv = (struct imxrt_driver_s *)arg; uint32_t flags; uint32_t mbi; uint32_t mb_bit; @@ -1246,10 +1318,6 @@ static void imxrt_txtimeout_work(void *arg) now.tv_sec = ts.tv_sec; now.tv_usec = ts.tv_nsec / 1000; - /* The watchdog timed out, yet we still check mailboxes in case the - * transmit function transmitted a new frame - */ - flags = getreg32(priv->base + IMXRT_CAN_IFLAG1_OFFSET); for (mbi = 0; mbi < TXMBRINGSIZE; mbi++) @@ -1288,7 +1356,6 @@ static void imxrt_txtimeout_work(void *arg) mb = flexcan_get_mb(priv, RXMBCOUNT + 1 + mbi); mb->cs.code = CAN_TXMB_ABORT; - priv->txmb[mbi].pending = TX_ABORT; } } @@ -1297,7 +1364,8 @@ static void imxrt_txtimeout_work(void *arg) * * Description: * Our TX watchdog timed out. Called from the timer interrupt handler. - * The last TX never completed. Reset the hardware and start again. + * Queue the same TX worker as the completion IRQ so the two cannot + * cancel each other. * * Input Parameters: * arg - The argument @@ -1314,10 +1382,7 @@ static void imxrt_txtimeout_expiry(wdparm_t arg) { struct imxrt_driver_s *priv = (struct imxrt_driver_s *)arg; - /* Schedule to perform the TX timeout processing on the worker thread - */ - - work_queue(CANWORK, &priv->irqwork, imxrt_txtimeout_work, priv, 0); + work_queue(CANWORK, &priv->irqwork, imxrt_tx_work, priv, 0); } #endif @@ -1428,6 +1493,8 @@ static int imxrt_ifup(struct net_driver_s *dev) } priv->bifup = true; + priv->bus_errors = 0; + priv->rx_overruns = 0; priv->txdesc = (struct can_frame *)&g_tx_pool; priv->rxdesc = (struct can_frame *)&g_rx_pool; if (priv->canfd_capable) @@ -1591,7 +1658,7 @@ static int imxrt_ioctl(struct net_driver_s *dev, int cmd, switch (cmd) { -#ifdef CONFIG_NETDEV_CAN_BITRATE_IOCTL +#ifdef CONFIG_NETDEV_CAN_IOCTL case SIOCGCANBITRATE: /* Get bitrate from a CAN controller */ { struct can_ioctl_data_s *req = @@ -1660,7 +1727,44 @@ static int imxrt_ioctl(struct net_driver_s *dev, int cmd, } } break; + + case SIOCGCANERRORS: + { + struct can_ioctl_errors_s *req = + (struct can_ioctl_errors_s *)((uintptr_t)arg); + uint32_t esr1 = imxrt_sample_errors(priv); + uint32_t ecr = getreg32(priv->base + IMXRT_CAN_ECR_OFFSET); + uint32_t flt = (esr1 & CAN_ESR1_FLTCONF_MASK) >> + CAN_ESR1_FLTCONF_SHIFT; + + if (flt >= 2) + { + req->state = CAN_ERRSTATE_BUSOFF; + } + else if (flt == 1) + { + req->state = CAN_ERRSTATE_PASSIVE; + } + else if (esr1 & (CAN_ESR1_TXWRN | CAN_ESR1_RXWRN)) + { + req->state = CAN_ERRSTATE_WARNING; + } + else + { + req->state = CAN_ERRSTATE_ACTIVE; + } + + req->txerr = (ecr & CAN_ECR_TXERRCNT_MASK) >> + CAN_ECR_TXERRCNT_SHIFT; + req->rxerr = (ecr & CAN_ECR_RXERRCNT_MASK) >> + CAN_ECR_RXERRCNT_SHIFT; + req->errors = priv->bus_errors; + req->rx_overruns = priv->rx_overruns; + ret = OK; + } + break; #endif + default: ret = -ENOTTY; break; diff --git a/arch/arm/src/kinetis/kinetis_flexcan.c b/arch/arm/src/kinetis/kinetis_flexcan.c index e93a41bb3ebc4..48db88f287df7 100644 --- a/arch/arm/src/kinetis/kinetis_flexcan.c +++ b/arch/arm/src/kinetis/kinetis_flexcan.c @@ -643,12 +643,14 @@ static int kinetis_transmit(struct kinetis_driver_s *priv) #ifdef CONFIG_NET_CAN_RAW_TX_DEADLINE struct timespec ts; + clock_systime_timespec(&ts); if (priv->dev.d_sndlen > priv->dev.d_len) { struct timeval *tv = (struct timeval *)(priv->dev.d_buf + priv->dev.d_len); + priv->txmb[mbi].deadline = *tv; timeout = (tv->tv_sec - ts.tv_sec)*CLK_TCK + ((tv->tv_usec - ts.tv_nsec / 1000)*CLK_TCK) / 1000000; @@ -683,9 +685,11 @@ static int kinetis_transmit(struct kinetis_driver_s *priv) (peak_tx_mailbox_index_ > mbi ? peak_tx_mailbox_index_ : mbi); union cs_e cs; + cs.cs = 0; cs.code = CAN_TXMB_DATAORREMOTE; struct mb_s *mb = &priv->tx[mbi]; + mb->cs.code = CAN_TXMB_INACTIVE; if (priv->dev.d_len == sizeof(struct can_frame)) @@ -1015,6 +1019,7 @@ static void kinetis_txdone(struct kinetis_driver_s *priv) wd_cancel(&priv->txtimeout[mbi]); struct mb_s *mb = &priv->tx[mbi]; + mb->cs.code = CAN_TXMB_INACTIVE; #endif } @@ -1084,6 +1089,7 @@ static int kinetis_flexcan_interrupt(int irq, void *context, if (irq == priv->config->mb_irq) { uint32_t flags; + flags = getreg32(priv->base + KINETIS_CAN_IFLAG1_OFFSET); flags &= IFLAG1_RX; @@ -1141,6 +1147,7 @@ static void kinetis_txtimeout_work(void *arg) struct timespec ts; struct timeval *now = (struct timeval *)&ts; + clock_systime_timespec(&ts); now->tv_usec = ts.tv_nsec / 1000; /* timespec to timeval conversion */ @@ -1166,6 +1173,7 @@ static void kinetis_txtimeout_work(void *arg) } struct mb_s *mb = &priv->tx[mbi]; + mb->cs.code = CAN_TXMB_ABORT; priv->txmb[mbi].pending = TX_ABORT; } @@ -1230,6 +1238,7 @@ static uint32_t kinetis_waitesr2_change(uint32_t base, uint32_t mask, for (wait_ack = 0; wait_ack < timeout; wait_ack++) { uint32_t state = (getreg32(base + KINETIS_CAN_ESR2_OFFSET) & mask); + if (state == target_state) { return true; @@ -1244,6 +1253,7 @@ static uint32_t kinetis_waitesr2_change(uint32_t base, uint32_t mask, static void kinetis_setfreeze(uint32_t base, uint32_t freeze) { uint32_t regval; + if (freeze) { /* Enter freeze mode */ @@ -1272,6 +1282,7 @@ static uint32_t kinetis_waitmcr_change(uint32_t base, uint32_t mask, { const bool state = (getreg32(base + KINETIS_CAN_MCR_OFFSET) & mask) != 0; + if (state == target_state) { return true; @@ -1477,7 +1488,7 @@ static int kinetis_txavail(struct net_driver_s *dev) * ****************************************************************************/ -#ifdef CONFIG_NETDEV_CAN_BITRATE_IOCTL +#ifdef CONFIG_NETDEV_CAN_IOCTL static int kinetis_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg) { @@ -1492,6 +1503,7 @@ static int kinetis_ioctl(struct net_driver_s *dev, int cmd, { struct can_ioctl_data_s *req = (struct can_ioctl_data_s *)((uintptr_t)arg); + req->arbi_bitrate = priv->arbi_timing.bitrate; req->arbi_samplep = priv->arbi_timing.samplep; #ifdef CONFIG_NET_CAN_CANFD @@ -1511,6 +1523,7 @@ static int kinetis_ioctl(struct net_driver_s *dev, int cmd, (struct can_ioctl_data_s *)((uintptr_t)arg); struct flexcan_timeseg arbi_timing; + arbi_timing.bitrate = req->arbi_bitrate; arbi_timing.samplep = req->arbi_samplep; @@ -1525,6 +1538,7 @@ static int kinetis_ioctl(struct net_driver_s *dev, int cmd, #ifdef CONFIG_NET_CAN_CANFD struct flexcan_timeseg data_timing; + data_timing.bitrate = req->data_bitrate; data_timing.samplep = req->data_samplep; @@ -1803,76 +1817,76 @@ int kinetis_caninitialize(int intf) switch (intf) { #ifdef CONFIG_KINETIS_FLEXCAN0 - case 0: - priv = &g_flexcan0; - memset(priv, 0, sizeof(struct kinetis_driver_s)); - priv->base = KINETIS_CAN0_BASE; - priv->config = &kinetis_flexcan0_config; + case 0: + priv = &g_flexcan0; + memset(priv, 0, sizeof(struct kinetis_driver_s)); + priv->base = KINETIS_CAN0_BASE; + priv->config = &kinetis_flexcan0_config; - /* Default bitrate configuration */ + /* Default bitrate configuration */ # ifdef CONFIG_NET_CAN_CANFD - priv->arbi_timing.bitrate = CONFIG_FLEXCAN0_ARBI_BITRATE; - priv->arbi_timing.samplep = CONFIG_FLEXCAN0_ARBI_SAMPLEP; - priv->data_timing.bitrate = CONFIG_FLEXCAN0_DATA_BITRATE; - priv->data_timing.samplep = CONFIG_FLEXCAN0_DATA_SAMPLEP; + priv->arbi_timing.bitrate = CONFIG_FLEXCAN0_ARBI_BITRATE; + priv->arbi_timing.samplep = CONFIG_FLEXCAN0_ARBI_SAMPLEP; + priv->data_timing.bitrate = CONFIG_FLEXCAN0_DATA_BITRATE; + priv->data_timing.samplep = CONFIG_FLEXCAN0_DATA_SAMPLEP; # else - priv->arbi_timing.bitrate = CONFIG_FLEXCAN0_BITRATE; - priv->arbi_timing.samplep = CONFIG_FLEXCAN0_SAMPLEP; + priv->arbi_timing.bitrate = CONFIG_FLEXCAN0_BITRATE; + priv->arbi_timing.samplep = CONFIG_FLEXCAN0_SAMPLEP; # endif - regval = getreg32(KINETIS_SIM_SCGC6); - regval |= SIM_SCGC6_FLEXCAN0; - putreg32(regval, KINETIS_SIM_SCGC6); - break; + regval = getreg32(KINETIS_SIM_SCGC6); + regval |= SIM_SCGC6_FLEXCAN0; + putreg32(regval, KINETIS_SIM_SCGC6); + break; #endif #ifdef CONFIG_KINETIS_FLEXCAN1 - case 1: - priv = &g_flexcan1; - memset(priv, 0, sizeof(struct kinetis_driver_s)); - priv->base = KINETIS_CAN1_BASE; - priv->config = &kinetis_flexcan1_config; + case 1: + priv = &g_flexcan1; + memset(priv, 0, sizeof(struct kinetis_driver_s)); + priv->base = KINETIS_CAN1_BASE; + priv->config = &kinetis_flexcan1_config; - /* Default bitrate configuration */ + /* Default bitrate configuration */ # ifdef CONFIG_NET_CAN_CANFD - priv->arbi_timing.bitrate = CONFIG_FLEXCAN1_ARBI_BITRATE; - priv->arbi_timing.samplep = CONFIG_FLEXCAN1_ARBI_SAMPLEP; - priv->data_timing.bitrate = CONFIG_FLEXCAN1_DATA_BITRATE; - priv->data_timing.samplep = CONFIG_FLEXCAN1_DATA_SAMPLEP; + priv->arbi_timing.bitrate = CONFIG_FLEXCAN1_ARBI_BITRATE; + priv->arbi_timing.samplep = CONFIG_FLEXCAN1_ARBI_SAMPLEP; + priv->data_timing.bitrate = CONFIG_FLEXCAN1_DATA_BITRATE; + priv->data_timing.samplep = CONFIG_FLEXCAN1_DATA_SAMPLEP; # else - priv->arbi_timing.bitrate = CONFIG_FLEXCAN1_BITRATE; - priv->arbi_timing.samplep = CONFIG_FLEXCAN1_SAMPLEP; + priv->arbi_timing.bitrate = CONFIG_FLEXCAN1_BITRATE; + priv->arbi_timing.samplep = CONFIG_FLEXCAN1_SAMPLEP; # endif - regval = getreg32(KINETIS_SIM_SCGC3); - regval |= SIM_SCGC3_FLEXCAN1; - putreg32(regval, KINETIS_SIM_SCGC3); - break; + regval = getreg32(KINETIS_SIM_SCGC3); + regval |= SIM_SCGC3_FLEXCAN1; + putreg32(regval, KINETIS_SIM_SCGC3); + break; #endif #ifdef CONFIG_KINETIS_FLEXCAN2 - case 2: - priv = &g_flexcan2; - memset(priv, 0, sizeof(struct kinetis_driver_s)); - priv->base = KINETIS_CAN2_BASE; - priv->config = &kinetis_flexcan2_config; + case 2: + priv = &g_flexcan2; + memset(priv, 0, sizeof(struct kinetis_driver_s)); + priv->base = KINETIS_CAN2_BASE; + priv->config = &kinetis_flexcan2_config; - /* Default bitrate configuration */ + /* Default bitrate configuration */ # ifdef CONFIG_NET_CAN_CANFD - priv->arbi_timing.bitrate = CONFIG_FLEXCAN2_ARBI_BITRATE; - priv->arbi_timing.samplep = CONFIG_FLEXCAN2_ARBI_SAMPLEP; - priv->data_timing.bitrate = CONFIG_FLEXCAN2_DATA_BITRATE; - priv->data_timing.samplep = CONFIG_FLEXCAN2_DATA_SAMPLEP; + priv->arbi_timing.bitrate = CONFIG_FLEXCAN2_ARBI_BITRATE; + priv->arbi_timing.samplep = CONFIG_FLEXCAN2_ARBI_SAMPLEP; + priv->data_timing.bitrate = CONFIG_FLEXCAN2_DATA_BITRATE; + priv->data_timing.samplep = CONFIG_FLEXCAN2_DATA_SAMPLEP; # else - priv->arbi_timing.bitrate = CONFIG_FLEXCAN2_BITRATE; - priv->arbi_timing.samplep = CONFIG_FLEXCAN2_SAMPLEP; + priv->arbi_timing.bitrate = CONFIG_FLEXCAN2_BITRATE; + priv->arbi_timing.samplep = CONFIG_FLEXCAN2_SAMPLEP; # endif - break; + break; #endif - default: - return -ENODEV; + default: + return -ENODEV; } if (!kinetis_bitratetotimeseg(&priv->arbi_timing, 1, 0)) diff --git a/arch/arm/src/s32k1xx/s32k1xx_flexcan.c b/arch/arm/src/s32k1xx/s32k1xx_flexcan.c index 519ade4919ea8..69061ab5370d2 100644 --- a/arch/arm/src/s32k1xx/s32k1xx_flexcan.c +++ b/arch/arm/src/s32k1xx/s32k1xx_flexcan.c @@ -645,12 +645,14 @@ static int s32k1xx_transmit(struct s32k1xx_driver_s *priv) #ifdef CONFIG_NET_CAN_RAW_TX_DEADLINE struct timespec ts; + clock_systime_timespec(&ts); if (priv->dev.d_sndlen > priv->dev.d_len) { struct timeval *tv = (struct timeval *)(priv->dev.d_buf + priv->dev.d_len); + priv->txmb[mbi].deadline = *tv; timeout = (tv->tv_sec - ts.tv_sec)*CLK_TCK + ((tv->tv_usec - ts.tv_nsec / 1000)*CLK_TCK) / 1000000; @@ -685,9 +687,11 @@ static int s32k1xx_transmit(struct s32k1xx_driver_s *priv) (peak_tx_mailbox_index_ > mbi ? peak_tx_mailbox_index_ : mbi); union cs_e cs; + cs.cs = 0; cs.code = CAN_TXMB_DATAORREMOTE; struct mb_s *mb = &priv->tx[mbi]; + mb->cs.code = CAN_TXMB_INACTIVE; if (priv->dev.d_len <= sizeof(struct can_frame)) @@ -1019,6 +1023,7 @@ static void s32k1xx_txdone(struct s32k1xx_driver_s *priv) wd_cancel(&priv->txtimeout[mbi]); struct mb_s *mb = &priv->tx[mbi]; + mb->cs.code = CAN_TXMB_INACTIVE; #endif } @@ -1088,6 +1093,7 @@ static int s32k1xx_flexcan_interrupt(int irq, void *context, if (irq == priv->config->mb_irq) { uint32_t flags; + flags = getreg32(priv->base + S32K1XX_CAN_IFLAG1_OFFSET); flags &= IFLAG1_RX; @@ -1145,6 +1151,7 @@ static void s32k1xx_txtimeout_work(void *arg) struct timespec ts; struct timeval *now = (struct timeval *)&ts; + clock_systime_timespec(&ts); now->tv_usec = ts.tv_nsec / 1000; /* timespec to timeval conversion */ @@ -1170,6 +1177,7 @@ static void s32k1xx_txtimeout_work(void *arg) } struct mb_s *mb = &priv->tx[mbi]; + mb->cs.code = CAN_TXMB_ABORT; priv->txmb[mbi].pending = TX_ABORT; } @@ -1229,6 +1237,7 @@ static void s32k1xx_setenable(uint32_t base, uint32_t enable) static void s32k1xx_setfreeze(uint32_t base, uint32_t freeze) { uint32_t regval; + if (freeze) { /* Enter freeze mode */ @@ -1257,6 +1266,7 @@ static uint32_t s32k1xx_waitmcr_change(uint32_t base, uint32_t mask, { const bool state = (getreg32(base + S32K1XX_CAN_MCR_OFFSET) & mask) != 0; + if (state == target_state) { return true; @@ -1460,7 +1470,7 @@ static int s32k1xx_txavail(struct net_driver_s *dev) * ****************************************************************************/ -#ifdef CONFIG_NETDEV_CAN_BITRATE_IOCTL +#ifdef CONFIG_NETDEV_CAN_IOCTL static int s32k1xx_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg) { @@ -1475,6 +1485,7 @@ static int s32k1xx_ioctl(struct net_driver_s *dev, int cmd, { struct can_ioctl_data_s *req = (struct can_ioctl_data_s *)((uintptr_t)arg); + req->arbi_bitrate = priv->arbi_timing.bitrate; req->arbi_samplep = priv->arbi_timing.samplep; #ifdef CONFIG_NET_CAN_CANFD @@ -1494,6 +1505,7 @@ static int s32k1xx_ioctl(struct net_driver_s *dev, int cmd, (struct can_ioctl_data_s *)((uintptr_t)arg); struct flexcan_timeseg arbi_timing; + arbi_timing.bitrate = req->arbi_bitrate; arbi_timing.samplep = req->arbi_samplep; @@ -1508,6 +1520,7 @@ static int s32k1xx_ioctl(struct net_driver_s *dev, int cmd, #ifdef CONFIG_NET_CAN_CANFD struct flexcan_timeseg data_timing; + data_timing.bitrate = req->data_bitrate; data_timing.samplep = req->data_samplep; @@ -1794,70 +1807,70 @@ int s32k1xx_caninitialize(int intf) switch (intf) { #ifdef CONFIG_S32K1XX_FLEXCAN0 - case 0: - priv = &g_flexcan0; - memset(priv, 0, sizeof(struct s32k1xx_driver_s)); - priv->base = S32K1XX_FLEXCAN0_BASE; - priv->config = &s32k1xx_flexcan0_config; + case 0: + priv = &g_flexcan0; + memset(priv, 0, sizeof(struct s32k1xx_driver_s)); + priv->base = S32K1XX_FLEXCAN0_BASE; + priv->config = &s32k1xx_flexcan0_config; - /* Default bitrate configuration */ + /* Default bitrate configuration */ # ifdef CONFIG_NET_CAN_CANFD - priv->arbi_timing.bitrate = CONFIG_FLEXCAN0_ARBI_BITRATE; - priv->arbi_timing.samplep = CONFIG_FLEXCAN0_ARBI_SAMPLEP; - priv->data_timing.bitrate = CONFIG_FLEXCAN0_DATA_BITRATE; - priv->data_timing.samplep = CONFIG_FLEXCAN0_DATA_SAMPLEP; + priv->arbi_timing.bitrate = CONFIG_FLEXCAN0_ARBI_BITRATE; + priv->arbi_timing.samplep = CONFIG_FLEXCAN0_ARBI_SAMPLEP; + priv->data_timing.bitrate = CONFIG_FLEXCAN0_DATA_BITRATE; + priv->data_timing.samplep = CONFIG_FLEXCAN0_DATA_SAMPLEP; # else - priv->arbi_timing.bitrate = CONFIG_FLEXCAN0_BITRATE; - priv->arbi_timing.samplep = CONFIG_FLEXCAN0_SAMPLEP; + priv->arbi_timing.bitrate = CONFIG_FLEXCAN0_BITRATE; + priv->arbi_timing.samplep = CONFIG_FLEXCAN0_SAMPLEP; # endif - break; + break; #endif #ifdef CONFIG_S32K1XX_FLEXCAN1 - case 1: - priv = &g_flexcan1; - memset(priv, 0, sizeof(struct s32k1xx_driver_s)); - priv->base = S32K1XX_FLEXCAN1_BASE; - priv->config = &s32k1xx_flexcan1_config; + case 1: + priv = &g_flexcan1; + memset(priv, 0, sizeof(struct s32k1xx_driver_s)); + priv->base = S32K1XX_FLEXCAN1_BASE; + priv->config = &s32k1xx_flexcan1_config; - /* Default bitrate configuration */ + /* Default bitrate configuration */ # ifdef CONFIG_NET_CAN_CANFD - priv->arbi_timing.bitrate = CONFIG_FLEXCAN1_ARBI_BITRATE; - priv->arbi_timing.samplep = CONFIG_FLEXCAN1_ARBI_SAMPLEP; - priv->data_timing.bitrate = CONFIG_FLEXCAN1_DATA_BITRATE; - priv->data_timing.samplep = CONFIG_FLEXCAN1_DATA_SAMPLEP; + priv->arbi_timing.bitrate = CONFIG_FLEXCAN1_ARBI_BITRATE; + priv->arbi_timing.samplep = CONFIG_FLEXCAN1_ARBI_SAMPLEP; + priv->data_timing.bitrate = CONFIG_FLEXCAN1_DATA_BITRATE; + priv->data_timing.samplep = CONFIG_FLEXCAN1_DATA_SAMPLEP; # else - priv->arbi_timing.bitrate = CONFIG_FLEXCAN1_BITRATE; - priv->arbi_timing.samplep = CONFIG_FLEXCAN1_SAMPLEP; + priv->arbi_timing.bitrate = CONFIG_FLEXCAN1_BITRATE; + priv->arbi_timing.samplep = CONFIG_FLEXCAN1_SAMPLEP; # endif - break; + break; #endif #ifdef CONFIG_S32K1XX_FLEXCAN2 - case 2: - priv = &g_flexcan2; - memset(priv, 0, sizeof(struct s32k1xx_driver_s)); - priv->base = S32K1XX_FLEXCAN2_BASE; - priv->config = &s32k1xx_flexcan2_config; + case 2: + priv = &g_flexcan2; + memset(priv, 0, sizeof(struct s32k1xx_driver_s)); + priv->base = S32K1XX_FLEXCAN2_BASE; + priv->config = &s32k1xx_flexcan2_config; - /* Default bitrate configuration */ + /* Default bitrate configuration */ # ifdef CONFIG_NET_CAN_CANFD - priv->arbi_timing.bitrate = CONFIG_FLEXCAN2_ARBI_BITRATE; - priv->arbi_timing.samplep = CONFIG_FLEXCAN2_ARBI_SAMPLEP; - priv->data_timing.bitrate = CONFIG_FLEXCAN2_DATA_BITRATE; - priv->data_timing.samplep = CONFIG_FLEXCAN2_DATA_SAMPLEP; + priv->arbi_timing.bitrate = CONFIG_FLEXCAN2_ARBI_BITRATE; + priv->arbi_timing.samplep = CONFIG_FLEXCAN2_ARBI_SAMPLEP; + priv->data_timing.bitrate = CONFIG_FLEXCAN2_DATA_BITRATE; + priv->data_timing.samplep = CONFIG_FLEXCAN2_DATA_SAMPLEP; # else - priv->arbi_timing.bitrate = CONFIG_FLEXCAN2_BITRATE; - priv->arbi_timing.samplep = CONFIG_FLEXCAN2_SAMPLEP; + priv->arbi_timing.bitrate = CONFIG_FLEXCAN2_BITRATE; + priv->arbi_timing.samplep = CONFIG_FLEXCAN2_SAMPLEP; # endif - break; + break; #endif - default: - return -ENODEV; + default: + return -ENODEV; } if (!s32k1xx_bitratetotimeseg(&priv->arbi_timing, 1, 0)) diff --git a/arch/arm/src/s32k3xx/s32k3xx_flexcan.c b/arch/arm/src/s32k3xx/s32k3xx_flexcan.c index f5aa309dea61b..f3deaf6083af9 100644 --- a/arch/arm/src/s32k3xx/s32k3xx_flexcan.c +++ b/arch/arm/src/s32k3xx/s32k3xx_flexcan.c @@ -805,12 +805,14 @@ static int s32k3xx_transmit(struct s32k3xx_driver_s *priv) #ifdef CONFIG_NET_CAN_RAW_TX_DEADLINE struct timespec ts; + clock_systime_timespec(&ts); if (priv->dev.d_sndlen > priv->dev.d_len) { struct timeval *tv = (struct timeval *)(priv->dev.d_buf + priv->dev.d_len); + priv->txmb[mbi].deadline = *tv; timeout = (tv->tv_sec - ts.tv_sec)*CLK_TCK + ((tv->tv_usec - ts.tv_nsec / 1000)*CLK_TCK) / 1000000; @@ -845,9 +847,11 @@ static int s32k3xx_transmit(struct s32k3xx_driver_s *priv) (peak_tx_mailbox_index_ > mbi ? peak_tx_mailbox_index_ : mbi); union cs_e cs; + cs.cs = 0; cs.code = CAN_TXMB_DATAORREMOTE; struct mb_s *mb = &priv->tx[mbi]; + mb->cs.code = CAN_TXMB_INACTIVE; if (priv->dev.d_len <= sizeof(struct can_frame)) @@ -1067,7 +1071,7 @@ static void s32k3xx_receive(struct s32k3xx_driver_s *priv, uint32_t flags) else /* CAN 2.0 Frame */ #endif { - struct can_frame *frame = (struct can_frame *)priv->rxdesc; + struct can_frame *frame = (struct can_frame *)priv->rxdesc; if (rf->cs.ide) { @@ -1175,6 +1179,7 @@ static void s32k3xx_txdone(struct s32k3xx_driver_s *priv) wd_cancel(&priv->txtimeout[mbi]); struct mb_s *mb = &priv->tx[mbi]; + mb->cs.code = CAN_TXMB_INACTIVE; #endif } @@ -1243,6 +1248,7 @@ static int s32k3xx_flexcan_interrupt(int irq, void *context, void *arg) if (irq == priv->config->mb_irq) { uint32_t flags; + flags = getreg32(priv->base + S32K3XX_CAN_IFLAG1_OFFSET); flags &= IFLAG1_RX; @@ -1300,6 +1306,7 @@ static void s32k3xx_txtimeout_work(void *arg) struct timespec ts; struct timeval *now = (struct timeval *)&ts; + clock_systime_timespec(&ts); now->tv_usec = ts.tv_nsec / 1000; /* timespec to timeval conversion */ @@ -1325,6 +1332,7 @@ static void s32k3xx_txtimeout_work(void *arg) } struct mb_s *mb = &priv->tx[mbi]; + mb->cs.code = CAN_TXMB_ABORT; priv->txmb[mbi].pending = TX_ABORT; } @@ -1384,6 +1392,7 @@ static void s32k3xx_setenable(uint32_t base, uint32_t enable) static void s32k3xx_setfreeze(uint32_t base, uint32_t freeze) { uint32_t regval; + if (freeze) { /* Enter freeze mode */ @@ -1412,6 +1421,7 @@ static uint32_t s32k3xx_waitmcr_change(uint32_t base, uint32_t mask, { const bool state = (getreg32(base + S32K3XX_CAN_MCR_OFFSET) & mask) != 0; + if (state == target_state) { return true; @@ -1658,11 +1668,12 @@ static int s32k3xx_ioctl(struct net_driver_s *dev, int cmd, switch (cmd) { -#ifdef CONFIG_NETDEV_CAN_BITRATE_IOCTL +#ifdef CONFIG_NETDEV_CAN_IOCTL case SIOCGCANBITRATE: /* Get bitrate from a CAN controller */ { struct can_ioctl_data_s *req = (struct can_ioctl_data_s *)((uintptr_t)arg); + req->arbi_bitrate = priv->arbi_timing.bitrate; req->arbi_samplep = priv->arbi_timing.samplep; #ifdef CONFIG_NET_CAN_CANFD @@ -1682,6 +1693,7 @@ static int s32k3xx_ioctl(struct net_driver_s *dev, int cmd, (struct can_ioctl_data_s *)((uintptr_t)arg); struct flexcan_timeseg arbi_timing; + arbi_timing.bitrate = req->arbi_bitrate; arbi_timing.samplep = req->arbi_samplep; @@ -1697,6 +1709,7 @@ static int s32k3xx_ioctl(struct net_driver_s *dev, int cmd, #ifdef CONFIG_NET_CAN_CANFD struct flexcan_timeseg data_timing; + data_timing.bitrate = req->data_bitrate; data_timing.samplep = req->data_samplep; @@ -2019,139 +2032,139 @@ int s32k3xx_caninitialize(int intf) switch (intf) { #ifdef CONFIG_S32K3XX_FLEXCAN0 - case 0: - priv = &g_flexcan0; - memset(priv, 0, sizeof(struct s32k3xx_driver_s)); - priv->base = S32K3XX_FLEXCAN0_BASE; - priv->config = &s32k3xx_flexcan0_config; - priv->clk_freq = s32k3xx_get_freq(FLEXCAN0_CLK); + case 0: + priv = &g_flexcan0; + memset(priv, 0, sizeof(struct s32k3xx_driver_s)); + priv->base = S32K3XX_FLEXCAN0_BASE; + priv->config = &s32k3xx_flexcan0_config; + priv->clk_freq = s32k3xx_get_freq(FLEXCAN0_CLK); - /* Default bitrate configuration */ + /* Default bitrate configuration */ # ifdef CONFIG_NET_CAN_CANFD - priv->arbi_timing.bitrate = CONFIG_FLEXCAN0_ARBI_BITRATE; - priv->arbi_timing.samplep = CONFIG_FLEXCAN0_ARBI_SAMPLEP; - priv->data_timing.bitrate = CONFIG_FLEXCAN0_DATA_BITRATE; - priv->data_timing.samplep = CONFIG_FLEXCAN0_DATA_SAMPLEP; + priv->arbi_timing.bitrate = CONFIG_FLEXCAN0_ARBI_BITRATE; + priv->arbi_timing.samplep = CONFIG_FLEXCAN0_ARBI_SAMPLEP; + priv->data_timing.bitrate = CONFIG_FLEXCAN0_DATA_BITRATE; + priv->data_timing.samplep = CONFIG_FLEXCAN0_DATA_SAMPLEP; # else - priv->arbi_timing.bitrate = CONFIG_FLEXCAN0_BITRATE; - priv->arbi_timing.samplep = CONFIG_FLEXCAN0_SAMPLEP; + priv->arbi_timing.bitrate = CONFIG_FLEXCAN0_BITRATE; + priv->arbi_timing.samplep = CONFIG_FLEXCAN0_SAMPLEP; # endif - break; + break; #endif #ifdef CONFIG_S32K3XX_FLEXCAN1 - case 1: - priv = &g_flexcan1; - memset(priv, 0, sizeof(struct s32k3xx_driver_s)); - priv->base = S32K3XX_FLEXCAN1_BASE; - priv->config = &s32k3xx_flexcan1_config; - priv->clk_freq = s32k3xx_get_freq(FLEXCAN1_CLK); + case 1: + priv = &g_flexcan1; + memset(priv, 0, sizeof(struct s32k3xx_driver_s)); + priv->base = S32K3XX_FLEXCAN1_BASE; + priv->config = &s32k3xx_flexcan1_config; + priv->clk_freq = s32k3xx_get_freq(FLEXCAN1_CLK); - /* Default bitrate configuration */ + /* Default bitrate configuration */ # ifdef CONFIG_NET_CAN_CANFD - priv->arbi_timing.bitrate = CONFIG_FLEXCAN1_ARBI_BITRATE; - priv->arbi_timing.samplep = CONFIG_FLEXCAN1_ARBI_SAMPLEP; - priv->data_timing.bitrate = CONFIG_FLEXCAN1_DATA_BITRATE; - priv->data_timing.samplep = CONFIG_FLEXCAN1_DATA_SAMPLEP; + priv->arbi_timing.bitrate = CONFIG_FLEXCAN1_ARBI_BITRATE; + priv->arbi_timing.samplep = CONFIG_FLEXCAN1_ARBI_SAMPLEP; + priv->data_timing.bitrate = CONFIG_FLEXCAN1_DATA_BITRATE; + priv->data_timing.samplep = CONFIG_FLEXCAN1_DATA_SAMPLEP; # else - priv->arbi_timing.bitrate = CONFIG_FLEXCAN1_BITRATE; - priv->arbi_timing.samplep = CONFIG_FLEXCAN1_SAMPLEP; + priv->arbi_timing.bitrate = CONFIG_FLEXCAN1_BITRATE; + priv->arbi_timing.samplep = CONFIG_FLEXCAN1_SAMPLEP; # endif - break; + break; #endif #ifdef CONFIG_S32K3XX_FLEXCAN2 - case 2: - priv = &g_flexcan2; - memset(priv, 0, sizeof(struct s32k3xx_driver_s)); - priv->base = S32K3XX_FLEXCAN2_BASE; - priv->config = &s32k3xx_flexcan2_config; - priv->clk_freq = s32k3xx_get_freq(FLEXCAN2_CLK); + case 2: + priv = &g_flexcan2; + memset(priv, 0, sizeof(struct s32k3xx_driver_s)); + priv->base = S32K3XX_FLEXCAN2_BASE; + priv->config = &s32k3xx_flexcan2_config; + priv->clk_freq = s32k3xx_get_freq(FLEXCAN2_CLK); - /* Default bitrate configuration */ + /* Default bitrate configuration */ # ifdef CONFIG_NET_CAN_CANFD - priv->arbi_timing.bitrate = CONFIG_FLEXCAN2_ARBI_BITRATE; - priv->arbi_timing.samplep = CONFIG_FLEXCAN2_ARBI_SAMPLEP; - priv->data_timing.bitrate = CONFIG_FLEXCAN2_DATA_BITRATE; - priv->data_timing.samplep = CONFIG_FLEXCAN2_DATA_SAMPLEP; + priv->arbi_timing.bitrate = CONFIG_FLEXCAN2_ARBI_BITRATE; + priv->arbi_timing.samplep = CONFIG_FLEXCAN2_ARBI_SAMPLEP; + priv->data_timing.bitrate = CONFIG_FLEXCAN2_DATA_BITRATE; + priv->data_timing.samplep = CONFIG_FLEXCAN2_DATA_SAMPLEP; # else - priv->arbi_timing.bitrate = CONFIG_FLEXCAN2_BITRATE; - priv->arbi_timing.samplep = CONFIG_FLEXCAN2_SAMPLEP; + priv->arbi_timing.bitrate = CONFIG_FLEXCAN2_BITRATE; + priv->arbi_timing.samplep = CONFIG_FLEXCAN2_SAMPLEP; # endif - break; + break; #endif #ifdef CONFIG_S32K3XX_FLEXCAN3 - case 3: - priv = &g_flexcan3; - memset(priv, 0, sizeof(struct s32k3xx_driver_s)); - priv->base = S32K3XX_FLEXCAN3_BASE; - priv->config = &s32k3xx_flexcan3_config; - priv->clk_freq = s32k3xx_get_freq(FLEXCAN3_CLK); + case 3: + priv = &g_flexcan3; + memset(priv, 0, sizeof(struct s32k3xx_driver_s)); + priv->base = S32K3XX_FLEXCAN3_BASE; + priv->config = &s32k3xx_flexcan3_config; + priv->clk_freq = s32k3xx_get_freq(FLEXCAN3_CLK); - /* Default bitrate configuration */ + /* Default bitrate configuration */ # ifdef CONFIG_NET_CAN_CANFD - priv->arbi_timing.bitrate = CONFIG_FLEXCAN3_ARBI_BITRATE; - priv->arbi_timing.samplep = CONFIG_FLEXCAN3_ARBI_SAMPLEP; - priv->data_timing.bitrate = CONFIG_FLEXCAN3_DATA_BITRATE; - priv->data_timing.samplep = CONFIG_FLEXCAN3_DATA_SAMPLEP; + priv->arbi_timing.bitrate = CONFIG_FLEXCAN3_ARBI_BITRATE; + priv->arbi_timing.samplep = CONFIG_FLEXCAN3_ARBI_SAMPLEP; + priv->data_timing.bitrate = CONFIG_FLEXCAN3_DATA_BITRATE; + priv->data_timing.samplep = CONFIG_FLEXCAN3_DATA_SAMPLEP; # else - priv->arbi_timing.bitrate = CONFIG_FLEXCAN3_BITRATE; - priv->arbi_timing.samplep = CONFIG_FLEXCAN3_SAMPLEP; + priv->arbi_timing.bitrate = CONFIG_FLEXCAN3_BITRATE; + priv->arbi_timing.samplep = CONFIG_FLEXCAN3_SAMPLEP; # endif - break; + break; #endif #ifdef CONFIG_S32K3XX_FLEXCAN4 - case 4: - priv = &g_flexcan4; - memset(priv, 0, sizeof(struct s32k3xx_driver_s)); - priv->base = S32K3XX_FLEXCAN4_BASE; - priv->config = &s32k3xx_flexcan4_config; - priv->clk_freq = s32k3xx_get_freq(FLEXCAN4_CLK); + case 4: + priv = &g_flexcan4; + memset(priv, 0, sizeof(struct s32k3xx_driver_s)); + priv->base = S32K3XX_FLEXCAN4_BASE; + priv->config = &s32k3xx_flexcan4_config; + priv->clk_freq = s32k3xx_get_freq(FLEXCAN4_CLK); - /* Default bitrate configuration */ + /* Default bitrate configuration */ # ifdef CONFIG_NET_CAN_CANFD - priv->arbi_timing.bitrate = CONFIG_FLEXCAN4_ARBI_BITRATE; - priv->arbi_timing.samplep = CONFIG_FLEXCAN4_ARBI_SAMPLEP; - priv->data_timing.bitrate = CONFIG_FLEXCAN4_DATA_BITRATE; - priv->data_timing.samplep = CONFIG_FLEXCAN4_DATA_SAMPLEP; + priv->arbi_timing.bitrate = CONFIG_FLEXCAN4_ARBI_BITRATE; + priv->arbi_timing.samplep = CONFIG_FLEXCAN4_ARBI_SAMPLEP; + priv->data_timing.bitrate = CONFIG_FLEXCAN4_DATA_BITRATE; + priv->data_timing.samplep = CONFIG_FLEXCAN4_DATA_SAMPLEP; # else - priv->arbi_timing.bitrate = CONFIG_FLEXCAN4_BITRATE; - priv->arbi_timing.samplep = CONFIG_FLEXCAN4_SAMPLEP; + priv->arbi_timing.bitrate = CONFIG_FLEXCAN4_BITRATE; + priv->arbi_timing.samplep = CONFIG_FLEXCAN4_SAMPLEP; # endif - break; + break; #endif #ifdef CONFIG_S32K3XX_FLEXCAN5 - case 5: - priv = &g_flexcan5; - memset(priv, 0, sizeof(struct s32k3xx_driver_s)); - priv->base = S32K3XX_FLEXCAN5_BASE; - priv->config = &s32k3xx_flexcan5_config; - priv->clk_freq = s32k3xx_get_freq(FLEXCAN5_CLK); + case 5: + priv = &g_flexcan5; + memset(priv, 0, sizeof(struct s32k3xx_driver_s)); + priv->base = S32K3XX_FLEXCAN5_BASE; + priv->config = &s32k3xx_flexcan5_config; + priv->clk_freq = s32k3xx_get_freq(FLEXCAN5_CLK); - /* Default bitrate configuration */ + /* Default bitrate configuration */ # ifdef CONFIG_NET_CAN_CANFD - priv->arbi_timing.bitrate = CONFIG_FLEXCAN5_ARBI_BITRATE; - priv->arbi_timing.samplep = CONFIG_FLEXCAN5_ARBI_SAMPLEP; - priv->data_timing.bitrate = CONFIG_FLEXCAN5_DATA_BITRATE; - priv->data_timing.samplep = CONFIG_FLEXCAN5_DATA_SAMPLEP; + priv->arbi_timing.bitrate = CONFIG_FLEXCAN5_ARBI_BITRATE; + priv->arbi_timing.samplep = CONFIG_FLEXCAN5_ARBI_SAMPLEP; + priv->data_timing.bitrate = CONFIG_FLEXCAN5_DATA_BITRATE; + priv->data_timing.samplep = CONFIG_FLEXCAN5_DATA_SAMPLEP; # else - priv->arbi_timing.bitrate = CONFIG_FLEXCAN5_BITRATE; - priv->arbi_timing.samplep = CONFIG_FLEXCAN5_SAMPLEP; + priv->arbi_timing.bitrate = CONFIG_FLEXCAN5_BITRATE; + priv->arbi_timing.samplep = CONFIG_FLEXCAN5_SAMPLEP; # endif - break; + break; #endif - default: - return -ENODEV; + default: + return -ENODEV; } if (!s32k3xx_bitratetotimeseg(&priv->arbi_timing, 1, 0, priv->clk_freq)) @@ -2187,7 +2200,7 @@ int s32k3xx_caninitialize(int intf) /* Attach the flexcan interrupt handler */ if (priv->config->bus_irq > 0) - { + { if (irq_attach(priv->config->bus_irq, s32k3xx_flexcan_interrupt, priv)) { /* We could not attach the ISR to the interrupt */ @@ -2195,10 +2208,10 @@ int s32k3xx_caninitialize(int intf) nerr("ERROR: Failed to attach CAN bus IRQ\n"); return -EAGAIN; } - } + } if (priv->config->error_irq > 0) - { + { if (irq_attach(priv->config->error_irq, s32k3xx_flexcan_interrupt, priv)) { @@ -2207,7 +2220,7 @@ int s32k3xx_caninitialize(int intf) nerr("ERROR: Failed to attach CAN error IRQ\n"); return -EAGAIN; } - } + } if (priv->config->lprx_irq > 0) { diff --git a/arch/arm/src/stm32h7/stm32_fdcan_sock.c b/arch/arm/src/stm32h7/stm32_fdcan_sock.c index 15eecf55a7ec6..1ae369be865fa 100644 --- a/arch/arm/src/stm32h7/stm32_fdcan_sock.c +++ b/arch/arm/src/stm32h7/stm32_fdcan_sock.c @@ -518,6 +518,7 @@ static void fdcan_dumpregs(struct fdcan_driver_s *priv) printf("CAN%d Base: 0x%lx\n", priv->iface_idx, priv->base); uint32_t regval; + regval = getreg32(priv->base + STM32_FDCAN_CCCR_OFFSET); printf("CCCR = 0x%lx\n", regval); regval = getreg32(priv->base + STM32_FDCAN_ECR_OFFSET); @@ -721,6 +722,7 @@ static bool fdcan_txringfull(struct fdcan_driver_s *priv) */ uint32_t regval = getreg32(priv->base + STM32_FDCAN_TXBC_OFFSET); + if ((regval & FDCAN_TXBC_TFQS) == 0) { nerr("No Tx FIFO buffers assigned? Check your message RAM config\n"); @@ -765,6 +767,7 @@ static int fdcan_transmit(struct fdcan_driver_s *priv) /* First, check if there are any slots available in the queue */ uint32_t regval = getreg32(priv->base + STM32_FDCAN_TXFQS_OFFSET); + if ((regval & FDCAN_TXFQS_TFQF) == FDCAN_TXFQS_TFQF) { /* Tx FIFO / Queue is full */ @@ -795,6 +798,7 @@ static int fdcan_transmit(struct fdcan_driver_s *priv) #ifdef CONFIG_NET_CAN_RAW_TX_DEADLINE int32_t timeout = 0; struct timespec ts; + clock_systime_timespec(&ts); if (priv->dev.d_sndlen > priv->dev.d_len) @@ -803,6 +807,7 @@ static int fdcan_transmit(struct fdcan_driver_s *priv) struct timeval *tv = (struct timeval *)(priv->dev.d_buf + priv->dev.d_len); + priv->txmb[mbi].deadline = *tv; timeout = (tv->tv_sec - ts.tv_sec)*CLK_TCK + ((tv->tv_usec - ts.tv_nsec / 1000)*CLK_TCK) / 1000000; @@ -1251,13 +1256,13 @@ static void fdcan_receive_work(void *arg) fdcan_check_errors(priv); #ifdef CONFIG_NET_CAN_ERRORS - uint32_t regval; + uint32_t regval; - /* Turning back on all configured RX error interrupts */ + /* Turning back on all configured RX error interrupts */ - regval = getreg32(priv->base + STM32_FDCAN_IE_OFFSET); - regval |= FDCAN_RXERR_INTS; - putreg32(regval, priv->base + STM32_FDCAN_IE_OFFSET); + regval = getreg32(priv->base + STM32_FDCAN_IE_OFFSET); + regval |= FDCAN_RXERR_INTS; + putreg32(regval, priv->base + STM32_FDCAN_IE_OFFSET); #endif leave_critical_section(flags); @@ -1285,6 +1290,7 @@ static void fdcan_txdone(struct fdcan_driver_s *priv) /* Read and reset the interrupt flag */ uint32_t ir = getreg32(priv->base + STM32_FDCAN_IR_OFFSET); + if (ir & FDCAN_IR_TC) { putreg32(FDCAN_IR_TC, priv->base + STM32_FDCAN_IR_OFFSET); @@ -1524,6 +1530,7 @@ static void fdcan_txtimeout_work(void *arg) struct timespec ts; struct timeval *now = (struct timeval *)&ts; + clock_systime_timespec(&ts); now->tv_usec = ts.tv_nsec / 1000; /* timespec to timeval conversion */ @@ -1697,9 +1704,11 @@ static bool fdcan_waitccr_change(uint32_t base, uint32_t mask, uint32_t target_state) { const unsigned timeout = 1000; + for (unsigned wait_ack = 0; wait_ack < timeout; wait_ack++) { const bool state = (getreg32(base + STM32_FDCAN_CCCR_OFFSET) & mask); + if (state == target_state) { return true; @@ -1730,6 +1739,7 @@ static void fdcan_enable_interrupts(struct fdcan_driver_s *priv) /* Enable both interrupt lines at the device level */ const uint32_t ile = FDCAN_ILE_EINT0 | FDCAN_ILE_EINT1; + modifyreg32(priv->base + STM32_FDCAN_ILE_OFFSET, 0, ile); /* Enable both lines at the NVIC level */ @@ -1762,6 +1772,7 @@ static void fdcan_disable_interrupts(struct fdcan_driver_s *priv) /* Disable both interrupt lines at the device level */ const uint32_t ile = FDCAN_ILE_EINT0 | FDCAN_ILE_EINT1; + modifyreg32(priv->base + STM32_FDCAN_ILE_OFFSET, ile, 0); } @@ -1956,11 +1967,12 @@ static int fdcan_netdev_ioctl(struct net_driver_s *dev, int cmd, switch (cmd) { -#ifdef CONFIG_NETDEV_CAN_BITRATE_IOCTL +#ifdef CONFIG_NETDEV_CAN_IOCTL case SIOCGCANBITRATE: /* Get bitrate from a CAN controller */ { struct can_ioctl_data_s *req = (struct can_ioctl_data_s *)((uintptr_t)arg); + req->arbi_bitrate = priv->arbi_timing.bitrate; #ifdef CONFIG_NET_CAN_CANFD req->data_bitrate = priv->data_timing.bitrate; @@ -1985,40 +1997,6 @@ static int fdcan_netdev_ioctl(struct net_driver_s *dev, int cmd, ret = OK; } break; -#endif /* CONFIG_NETDEV_CAN_BITRATE_IOCTL */ - -#ifdef CONFIG_NETDEV_CAN_FILTER_IOCTL - case SIOCACANEXTFILTER: - { - /* TODO: Add hardware-level filter... */ - - stm32_addextfilter(priv, (struct canioc_extfilter_s *)arg); - } - break; - - case SIOCDCANEXTFILTER: - { - /* TODO: Delete hardware-level filter... */ - - stm32_delextfilter(priv, (struct canioc_extfilter_s *)arg); - } - break; - - case SIOCACANSTDFILTER: - { - /* TODO: Add hardware-level filter... */ - - stm32_addstdfilter(priv, (struct canioc_stdfilter_s *)arg); - } - break; - - case SIOCDCANSTDFILTER: - { - /* TODO: Delete hardware-level filter... */ - - stm32_delstdfilter(priv, (struct canioc_stdfilter_s *)arg); - } - break; #endif default: @@ -2094,6 +2072,7 @@ int fdcan_initialize(struct fdcan_driver_s *priv) #ifdef CONFIG_STM32_FDCAN_REGDEBUG const struct fdcan_bitseg *tim = &priv->arbi_timing; + ninfo("[fdcan][arbi] Timings: presc=%u sjw=%u bs1=%u bs2=%u\r\n", tim->prescaler, tim->sjw, tim->bs1, tim->bs2); #endif @@ -2244,6 +2223,7 @@ int fdcan_initialize(struct fdcan_driver_s *priv) /* Standard ID Filters: Allow space for 128 filters (128 words) */ const uint8_t n_stdid = 128; + priv->message_ram.filt_stdid_addr = gl_ram_base + ram_offset * WORD_LENGTH; regval = (n_stdid << FDCAN_SIDFC_LSS_SHIFT) & FDCAN_SIDFC_LSS_MASK; @@ -2271,6 +2251,7 @@ int fdcan_initialize(struct fdcan_driver_s *priv) */ const uint8_t n_extid = 128; + priv->message_ram.filt_extid_addr = gl_ram_base + ram_offset * WORD_LENGTH; regval = (n_extid << FDCAN_XIDFC_LSE_SHIFT) & FDCAN_XIDFC_LSE_MASK; @@ -2459,64 +2440,64 @@ int stm32_fdcansockinitialize(int intf) switch (intf) { #ifdef CONFIG_STM32_FDCAN1 - case 0: - priv = &g_fdcan0; - memset(priv, 0, sizeof(struct fdcan_driver_s)); - priv->base = STM32_FDCAN1_BASE; - priv->iface_idx = 0; - priv->config = &stm32_fdcan0_config; + case 0: + priv = &g_fdcan0; + memset(priv, 0, sizeof(struct fdcan_driver_s)); + priv->base = STM32_FDCAN1_BASE; + priv->iface_idx = 0; + priv->config = &stm32_fdcan0_config; - /* Default bitrate configuration */ + /* Default bitrate configuration */ # ifdef CONFIG_NET_CAN_CANFD - priv->arbi_timing.bitrate = CONFIG_FDCAN1_ARBI_BITRATE; - priv->data_timing.bitrate = CONFIG_FDCAN1_DATA_BITRATE; + priv->arbi_timing.bitrate = CONFIG_FDCAN1_ARBI_BITRATE; + priv->data_timing.bitrate = CONFIG_FDCAN1_DATA_BITRATE; # else - priv->arbi_timing.bitrate = CONFIG_FDCAN1_BITRATE; + priv->arbi_timing.bitrate = CONFIG_FDCAN1_BITRATE; # endif - break; + break; #endif #ifdef CONFIG_STM32_FDCAN2 - case 1: - priv = &g_fdcan1; - memset(priv, 0, sizeof(struct fdcan_driver_s)); - priv->base = STM32_FDCAN2_BASE; - priv->iface_idx = 1; - priv->config = &stm32_fdcan1_config; + case 1: + priv = &g_fdcan1; + memset(priv, 0, sizeof(struct fdcan_driver_s)); + priv->base = STM32_FDCAN2_BASE; + priv->iface_idx = 1; + priv->config = &stm32_fdcan1_config; - /* Default bitrate configuration */ + /* Default bitrate configuration */ # ifdef CONFIG_NET_CAN_CANFD - priv->arbi_timing.bitrate = CONFIG_FDCAN2_ARBI_BITRATE; - priv->data_timing.bitrate = CONFIG_FDCAN2_DATA_BITRATE; + priv->arbi_timing.bitrate = CONFIG_FDCAN2_ARBI_BITRATE; + priv->data_timing.bitrate = CONFIG_FDCAN2_DATA_BITRATE; # else - priv->arbi_timing.bitrate = CONFIG_FDCAN2_BITRATE; + priv->arbi_timing.bitrate = CONFIG_FDCAN2_BITRATE; # endif - break; + break; #endif #ifdef CONFIG_STM32_FDCAN3 - case 2: - priv = &g_fdcan2; - memset(priv, 0, sizeof(struct fdcan_driver_s)); - priv->base = STM32_FDCAN3_BASE; - priv->iface_idx = 2; - priv->config = &stm32_fdcan2_config; + case 2: + priv = &g_fdcan2; + memset(priv, 0, sizeof(struct fdcan_driver_s)); + priv->base = STM32_FDCAN3_BASE; + priv->iface_idx = 2; + priv->config = &stm32_fdcan2_config; - /* Default bitrate configuration */ + /* Default bitrate configuration */ # ifdef CONFIG_NET_CAN_CANFD - priv->arbi_timing.bitrate = CONFIG_FDCAN3_ARBI_BITRATE; - priv->data_timing.bitrate = CONFIG_FDCAN3_DATA_BITRATE; + priv->arbi_timing.bitrate = CONFIG_FDCAN3_ARBI_BITRATE; + priv->data_timing.bitrate = CONFIG_FDCAN3_DATA_BITRATE; # else - priv->arbi_timing.bitrate = CONFIG_FDCAN3_BITRATE; + priv->arbi_timing.bitrate = CONFIG_FDCAN3_BITRATE; # endif - break; + break; #endif - default: - return -ENODEV; + default: + return -ENODEV; } if (fdcan_bittiming(&priv->arbi_timing) != OK) diff --git a/arch/arm64/src/imx9/imx9_flexcan.c b/arch/arm64/src/imx9/imx9_flexcan.c index 7936477dce5d2..7ca08ee1b8435 100644 --- a/arch/arm64/src/imx9/imx9_flexcan.c +++ b/arch/arm64/src/imx9/imx9_flexcan.c @@ -554,7 +554,7 @@ static int imx9_ioctl(struct net_driver_s *dev, int cmd, /* CAN ID filtering */ -#ifdef CONFIG_NETDEV_CAN_FILTER_IOCTL +#ifdef CONFIG_NETDEV_CAN_IOCTL static uint32_t imx9_add_filter(struct imx9_driver_s *priv, uint8_t filter_type, bool ext_id, @@ -594,6 +594,7 @@ static bool imx9_txringfull(struct imx9_driver_s *priv) for (mbi = RXMBCOUNT; mbi < TOTALMBCOUNT; mbi++) { volatile struct mb_s *mb = flexcan_get_mb(priv, mbi); + if (CAN_MB_CS_CODE(mb->cs) != CAN_TXMB_DATAORREMOTE) { return false; @@ -662,6 +663,7 @@ static int imx9_transmit(struct imx9_driver_s *priv) #ifdef CONFIG_NET_CAN_RAW_TX_DEADLINE struct timespec ts; + clock_systime_timespec(&ts); if (priv->dev.d_sndlen > priv->dev.d_len) @@ -702,6 +704,7 @@ static int imx9_transmit(struct imx9_driver_s *priv) if (priv->dev.d_len == sizeof(struct can_frame)) { struct can_frame *frame = (struct can_frame *)priv->dev.d_buf; + can_id = frame->can_id; len = 8; can_dlc = frame->can_dlc; @@ -711,6 +714,7 @@ static int imx9_transmit(struct imx9_driver_s *priv) else { struct canfd_frame *frame = (struct canfd_frame *)priv->dev.d_buf; + cs |= CAN_MB_CS_EDL; cs |= frame->flags & CANFD_BRS ? CAN_MB_CS_BRS : 0; can_id = frame->can_id; @@ -898,6 +902,7 @@ static void imx9_receive(struct imx9_driver_s *priv) size_t frame_len; uint32_t flags = getreg32(priv->base + IMX9_CAN_IFLAG1_OFFSET); + flags &= IFLAG1_RX; while (flags != 0) @@ -1278,6 +1283,7 @@ static void imx9_txtimeout_work(void *arg) volatile struct mb_s *mb; struct timespec ts; struct timeval *now = (struct timeval *)&ts; + clock_systime_timespec(&ts); now->tv_usec = ts.tv_nsec / 1000; /* timespec to timeval conversion */ @@ -1607,12 +1613,13 @@ static int imx9_ioctl(struct net_driver_s *dev, int cmd, switch (cmd) { -#ifdef CONFIG_NETDEV_CAN_BITRATE_IOCTL +#ifdef CONFIG_NETDEV_CAN_IOCTL case SIOCGCANBITRATE: /* Get bitrate from a CAN controller */ { struct imx9_driver_s *priv = (struct imx9_driver_s *)dev; struct can_ioctl_data_s *req = (struct can_ioctl_data_s *)((uintptr_t)arg); + req->arbi_bitrate = priv->arbi_timing.bitrate; req->arbi_samplep = priv->arbi_timing.samplep; if (priv->canfd_capable) @@ -1654,26 +1661,25 @@ static int imx9_ioctl(struct net_driver_s *dev, int cmd, priv->arbi_timing = arbi_timing; if (priv->canfd_capable) - { - priv->data_timing = data_timing; - } + { + priv->data_timing = data_timing; + } } } break; -#endif -#ifdef CONFIG_NETDEV_CAN_FILTER_IOCTL case SIOCACANSTDFILTER: /* Set STD ID CAN filter */ { struct imx9_driver_s *priv = (struct imx9_driver_s *)dev; struct can_ioctl_filter_s *req = (struct can_ioctl_filter_s *)((uintptr_t)arg); + if (!req) { return -EINVAL; } - ret = imx9_add_filter(priv, req->ftype, 0, req->fid1, req->fid2); + ret = imx9_add_filter(priv, req->ftype, 0, req->fid1, req->fid2); } break; @@ -1682,12 +1688,13 @@ static int imx9_ioctl(struct net_driver_s *dev, int cmd, struct imx9_driver_s *priv = (struct imx9_driver_s *)dev; struct can_ioctl_filter_s *req = (struct can_ioctl_filter_s *)((uintptr_t)arg); + if (!req) { return -EINVAL; } - ret = imx9_add_filter(priv, req->ftype, 1, req->fid1, req->fid2); + ret = imx9_add_filter(priv, req->ftype, 1, req->fid1, req->fid2); } break; @@ -1695,6 +1702,7 @@ static int imx9_ioctl(struct net_driver_s *dev, int cmd, case SIOCDCANEXTFILTER: /* Reset EXT ID CAN filter */ { struct imx9_driver_s *priv = (struct imx9_driver_s *)dev; + ret = imx9_reset_filter(priv); } break; @@ -1728,7 +1736,7 @@ static int imx9_ioctl(struct net_driver_s *dev, int cmd, * ****************************************************************************/ -#ifdef CONFIG_NETDEV_CAN_FILTER_IOCTL +#ifdef CONFIG_NETDEV_CAN_IOCTL static uint32_t imx9_add_filter(struct imx9_driver_s *priv, uint8_t filter_type, bool ext_id, @@ -1869,7 +1877,7 @@ static uint8_t imx9_reset_filter(struct imx9_driver_s *priv) return OK; } -#endif /* CONFIG_NETDEV_CAN_FILTER_IOCTL */ +#endif /* CONFIG_NETDEV_CAN_IOCTL */ /**************************************************************************** * Function: imx9_init_eccram @@ -2216,23 +2224,23 @@ int imx9_caninitialize(int intf) switch (intf) { #ifdef CONFIG_IMX9_FLEXCAN1 - case 1: - imx9_ccm_configure_root_clock(CCM_CR_CAN1, SYS_PLL1PFD1DIV2, 5); - imx9_ccm_gate_on(CCM_LPCG_CAN1, true); - priv = &g_flexcan1; - break; + case 1: + imx9_ccm_configure_root_clock(CCM_CR_CAN1, SYS_PLL1PFD1DIV2, 5); + imx9_ccm_gate_on(CCM_LPCG_CAN1, true); + priv = &g_flexcan1; + break; #endif #ifdef CONFIG_IMX9_FLEXCAN2 - case 2: - imx9_ccm_configure_root_clock(CCM_CR_CAN2, SYS_PLL1PFD1DIV2, 5); - imx9_ccm_gate_on(CCM_LPCG_CAN2, true); - priv = &g_flexcan2; - break; + case 2: + imx9_ccm_configure_root_clock(CCM_CR_CAN2, SYS_PLL1PFD1DIV2, 5); + imx9_ccm_gate_on(CCM_LPCG_CAN2, true); + priv = &g_flexcan2; + break; #endif - default: - return -ENODEV; + default: + return -ENODEV; } /* Get and store the clock (should be 80 MHz now) */ diff --git a/arch/risc-v/src/mpfs/mpfs_can.c b/arch/risc-v/src/mpfs/mpfs_can.c index 7c2cd99af5c80..e8e814526ee5d 100644 --- a/arch/risc-v/src/mpfs/mpfs_can.c +++ b/arch/risc-v/src/mpfs/mpfs_can.c @@ -474,12 +474,12 @@ static int mpfs_interrupt(int irq, void *context, void *arg); /* RX SW/HW filter related functions */ -#ifdef CONFIG_NETDEV_CAN_FILTER_IOCTL +#ifdef CONFIG_NETDEV_CAN_IOCTL static uint8_t mpfs_can_add_filter(mpfs_can_instance_t *priv, uint8_t filter_type, uint32_t filter_id1, uint32_t filter_id2); -#endif /* CONFIG_NETDEV_CAN_FILTER_IOCTL */ +#endif /* CONFIG_NETDEV_CAN_IOCTL */ static uint8_t mpfs_can_reset_filter(mpfs_can_instance_t *priv); @@ -523,7 +523,7 @@ static uint32_t mpfs_can_canid_to_msgid(uint32_t canid); static uint32_t mpfs_can_msgid_to_canid(uint32_t id, bool ide, bool rtr); static uint8_t mpfs_can_set_bitrate(mpfs_can_instance_t *priv, uint32_t bitrate); -#if defined(CONFIG_DEBUG_NET_INFO) || defined(CONFIG_NETDEV_CAN_BITRATE_IOCTL) +#if defined(CONFIG_DEBUG_NET_INFO) || defined(CONFIG_NETDEV_CAN_IOCTL) static uint32_t mpfs_can_get_sample_point(mpfs_can_instance_t *priv); #endif @@ -1081,7 +1081,7 @@ static int mpfs_interrupt(int irq, void *context, void *arg) * ****************************************************************************/ -#ifdef CONFIG_NETDEV_CAN_FILTER_IOCTL +#ifdef CONFIG_NETDEV_CAN_IOCTL static uint8_t mpfs_can_add_filter(mpfs_can_instance_t *priv, uint8_t filter_type, uint32_t filter_id1, @@ -1137,7 +1137,7 @@ static uint8_t mpfs_can_add_filter(mpfs_can_instance_t *priv, return CAN_OK; } -#endif /* CONFIG_NETDEV_CAN_FILTER_IOCTL */ +#endif /* CONFIG_NETDEV_CAN_IOCTL */ /**************************************************************************** * Name: mpfs_can_reset_filter @@ -1371,6 +1371,7 @@ static void mpfs_can_set_int_ebl(mpfs_can_instance_t *priv, uint32_t flag) { uint32_t reg = mpfs_can_get_int_ebl(priv); + putreg32(reg | flag, priv->reg_base + MPFS_CAN_INT_ENABLE_OFFSET); } @@ -1414,6 +1415,7 @@ static void mpfs_can_clear_int_ebl(mpfs_can_instance_t *priv, uint32_t flag) { uint32_t reg = mpfs_can_get_int_ebl(priv); + putreg32(reg & ~flag, priv->reg_base + MPFS_CAN_INT_ENABLE_OFFSET); } @@ -1530,6 +1532,7 @@ static uint32_t mpfs_can_get_int_status(mpfs_can_instance_t *priv) static uint8_t mpfs_can_get_error_status(mpfs_can_instance_t *priv) { uint32_t reg = getreg32(priv->reg_base + MPFS_CAN_ERROR_STATUS_OFFSET); + reg = ((reg & MPFS_CAN_ERROR_STATUS_ERROR_STATE) >> MPFS_CAN_ERROR_STATUS_ERROR_STATE_SHIFT); return (uint8_t)reg; @@ -1734,7 +1737,7 @@ static uint8_t mpfs_can_set_bitrate(mpfs_can_instance_t *priv, return CAN_OK; } -#if defined(CONFIG_DEBUG_NET_INFO) || defined(CONFIG_NETDEV_CAN_BITRATE_IOCTL) +#if defined(CONFIG_DEBUG_NET_INFO) || defined(CONFIG_NETDEV_CAN_IOCTL) /**************************************************************************** * Name: mpfs_can_get_sample_point * @@ -1760,12 +1763,14 @@ static uint8_t mpfs_can_set_bitrate(mpfs_can_instance_t *priv, static uint32_t mpfs_can_get_sample_point(mpfs_can_instance_t *priv) { uint32_t reg; + reg = getreg32(priv->reg_base + MPFS_CAN_CAN_CONFIG_OFFSET); uint32_t tseg1 = ((reg & MPFS_CAN_CAN_CONFIG_CFG_TSEG1) >> MPFS_CAN_CAN_CONFIG_CFG_TSEG1_SHIFT) + 1; uint32_t tseg2 = ((reg & MPFS_CAN_CAN_CONFIG_CFG_TSEG2) >> MPFS_CAN_CAN_CONFIG_CFG_TSEG2_SHIFT) + 1; const uint32_t sync_seg = 1; + return (sync_seg + tseg1) * 100 / (sync_seg + tseg1 + tseg2); } #endif @@ -1838,7 +1843,7 @@ static uint8_t mpfs_can_config_buffer(mpfs_can_instance_t *priv) mpfs_can_config_buffer_n(priv, buffer_number, &canrxobj); } - success = CAN_OK; + success = CAN_OK; } return success; @@ -1945,6 +1950,7 @@ mpfs_can_get_rx_buffer_status(mpfs_can_instance_t *priv) static uint32_t mpfs_can_get_rx_error_count(mpfs_can_instance_t *priv) { uint32_t reg = getreg32(priv->reg_base + MPFS_CAN_ERROR_STATUS_OFFSET); + reg = ((reg & MPFS_CAN_ERROR_STATUS_RX_ERR_CNT) >> MPFS_CAN_ERROR_STATUS_RX_ERR_CNT_SHIFT); return reg; @@ -1976,6 +1982,7 @@ static uint32_t mpfs_can_get_rx_error_count(mpfs_can_instance_t *priv) static inline bool mpfs_can_get_rx_gte96(mpfs_can_instance_t *priv) { uint32_t reg = getreg32(priv->reg_base + MPFS_CAN_ERROR_STATUS_OFFSET); + reg &= MPFS_CAN_ERROR_STATUS_RXGTE96; return (bool)reg; } @@ -2088,6 +2095,7 @@ static uint32_t mpfs_can_get_tx_buffer_status(mpfs_can_instance_t *priv) static uint32_t mpfs_can_get_tx_error_count(mpfs_can_instance_t *priv) { uint32_t reg = getreg32(priv->reg_base + MPFS_CAN_ERROR_STATUS_OFFSET); + reg = ((reg & MPFS_CAN_ERROR_STATUS_TX_ERR_CNT) >> MPFS_CAN_ERROR_STATUS_TX_ERR_CNT_SHIFT); return reg; @@ -2119,6 +2127,7 @@ static uint32_t mpfs_can_get_tx_error_count(mpfs_can_instance_t *priv) static inline bool mpfs_can_get_tx_gte96(mpfs_can_instance_t *priv) { uint32_t reg = getreg32(priv->reg_base + MPFS_CAN_ERROR_STATUS_OFFSET); + reg &= MPFS_CAN_ERROR_STATUS_TXGTE96; return (bool)reg; } @@ -2299,8 +2308,7 @@ static int mpfs_ioctl(struct netdev_lowerhalf_s *dev, int cmd, { ninfo("IOCTL received | cmd: %d arg: %ld\n", cmd, arg); -#if defined(CONFIG_NETDEV_CAN_BITRATE_IOCTL) || \ -defined(CONFIG_NETDEV_CAN_FILTER_IOCTL) +#ifdef CONFIG_NETDEV_CAN_IOCTL mpfs_can_instance_t *priv = (mpfs_can_instance_t *)dev; #endif @@ -2308,73 +2316,72 @@ defined(CONFIG_NETDEV_CAN_FILTER_IOCTL) switch (cmd) { -#ifdef CONFIG_NETDEV_CAN_BITRATE_IOCTL - case SIOCGCANBITRATE: - - /* Get bitrate from the CAN controller */ - - { - struct can_ioctl_data_s *req = - (struct can_ioctl_data_s *)((uintptr_t)arg); - req->arbi_bitrate = priv->bitrate_value; - req->arbi_samplep = mpfs_can_get_sample_point(priv); - ret = CAN_OK; - } - break; - - case SIOCSCANBITRATE: - - /* Set bitrate of the CAN controller */ - - { - struct can_ioctl_data_s *req = - (struct can_ioctl_data_s *)((uintptr_t)arg); - - if (CAN_OK != mpfs_can_set_bitrate(priv, req->arbi_bitrate)) - { - nerr("CAN controller bitrate set failed"); - ret = -EAGAIN; - break; - } - - ret = CAN_OK; - } - break; -#endif /* CONFIG_NETDEV_CAN_BITRATE_IOCTL */ - -#ifdef CONFIG_NETDEV_CAN_FILTER_IOCTL - case SIOCACANSTDFILTER: - case SIOCACANEXTFILTER: - - { - struct can_ioctl_filter_s *req = - (struct can_ioctl_filter_s *)((uintptr_t)arg); - - if (CAN_OK != mpfs_can_add_filter(priv, req->ftype, - req->fid1, req->fid2)) - { - nerr("CAN filter add failed"); - ret = -EINVAL; - break; - } - - ret = CAN_OK; - } - break; - - case SIOCDCANSTDFILTER: - case SIOCDCANEXTFILTER: - - { - mpfs_can_reset_filter(priv); - ret = CAN_OK; - } - break; -#endif /* CONFIG_NETDEV_CAN_FILTER_IOCTL */ - - default: - ret = -ENOTTY; - break; +#ifdef CONFIG_NETDEV_CAN_IOCTL + case SIOCGCANBITRATE: + + /* Get bitrate from the CAN controller */ + + { + struct can_ioctl_data_s *req = + (struct can_ioctl_data_s *)((uintptr_t)arg); + + req->arbi_bitrate = priv->bitrate_value; + req->arbi_samplep = mpfs_can_get_sample_point(priv); + ret = CAN_OK; + } + break; + + case SIOCSCANBITRATE: + + /* Set bitrate of the CAN controller */ + + { + struct can_ioctl_data_s *req = + (struct can_ioctl_data_s *)((uintptr_t)arg); + + if (CAN_OK != mpfs_can_set_bitrate(priv, req->arbi_bitrate)) + { + nerr("CAN controller bitrate set failed"); + ret = -EAGAIN; + break; + } + + ret = CAN_OK; + } + break; + + case SIOCACANSTDFILTER: + case SIOCACANEXTFILTER: + + { + struct can_ioctl_filter_s *req = + (struct can_ioctl_filter_s *)((uintptr_t)arg); + + if (CAN_OK != mpfs_can_add_filter(priv, req->ftype, + req->fid1, req->fid2)) + { + nerr("CAN filter add failed"); + ret = -EINVAL; + break; + } + + ret = CAN_OK; + } + break; + + case SIOCDCANSTDFILTER: + case SIOCDCANEXTFILTER: + + { + mpfs_can_reset_filter(priv); + ret = CAN_OK; + } + break; +#endif /* CONFIG_NETDEV_CAN_IOCTL */ + + default: + ret = -ENOTTY; + break; } return ret; diff --git a/boards/arm/at32/at32f437-mini/configs/can_socket/defconfig b/boards/arm/at32/at32f437-mini/configs/can_socket/defconfig index a35c092537e33..7d2f6556e37eb 100644 --- a/boards/arm/at32/at32f437-mini/configs/can_socket/defconfig +++ b/boards/arm/at32/at32f437-mini/configs/can_socket/defconfig @@ -38,7 +38,7 @@ CONFIG_INIT_ENTRYPOINT="nsh_main" CONFIG_INTELHEX_BINARY=y CONFIG_LINE_MAX=64 CONFIG_NET=y -CONFIG_NETDEV_CAN_BITRATE_IOCTL=y +CONFIG_NETDEV_CAN_IOCTL=y CONFIG_NETDEV_IFINDEX=y CONFIG_NET_CAN=y CONFIG_NET_CAN_SOCK_OPTS=y diff --git a/boards/arm/imx9/imx95-evk/configs/can/defconfig b/boards/arm/imx9/imx95-evk/configs/can/defconfig index 7510776e90a63..fb147108d64f1 100644 --- a/boards/arm/imx9/imx95-evk/configs/can/defconfig +++ b/boards/arm/imx9/imx95-evk/configs/can/defconfig @@ -54,7 +54,7 @@ CONFIG_IOB_THROTTLE=8 CONFIG_LIBC_LOCALTIME=y CONFIG_LPUART3_SERIAL_CONSOLE=y CONFIG_NET=y -CONFIG_NETDEV_CAN_BITRATE_IOCTL=y +CONFIG_NETDEV_CAN_IOCTL=y CONFIG_NETDEV_IFINDEX=y CONFIG_NETDEV_LATEINIT=y CONFIG_NET_CAN=y diff --git a/boards/arm/stm32h7/linum-stm32h753bi/configs/socketcan/defconfig b/boards/arm/stm32h7/linum-stm32h753bi/configs/socketcan/defconfig index 7ef37a7cbf763..0e9a1e41a1a7a 100644 --- a/boards/arm/stm32h7/linum-stm32h753bi/configs/socketcan/defconfig +++ b/boards/arm/stm32h7/linum-stm32h753bi/configs/socketcan/defconfig @@ -44,7 +44,7 @@ CONFIG_INTELHEX_BINARY=y CONFIG_LINE_MAX=64 CONFIG_MM_REGIONS=4 CONFIG_NET=y -CONFIG_NETDEV_CAN_BITRATE_IOCTL=y +CONFIG_NETDEV_CAN_IOCTL=y CONFIG_NETDEV_IFINDEX=y CONFIG_NETDEV_LATEINIT=y CONFIG_NET_CAN=y diff --git a/boards/arm/stm32h7/nucleo-h743zi2/configs/socketcan/defconfig b/boards/arm/stm32h7/nucleo-h743zi2/configs/socketcan/defconfig index 68c89eacc79d3..66d1e74be6618 100644 --- a/boards/arm/stm32h7/nucleo-h743zi2/configs/socketcan/defconfig +++ b/boards/arm/stm32h7/nucleo-h743zi2/configs/socketcan/defconfig @@ -40,7 +40,7 @@ CONFIG_INTELHEX_BINARY=y CONFIG_LINE_MAX=64 CONFIG_MM_REGIONS=4 CONFIG_NET=y -CONFIG_NETDEV_CAN_BITRATE_IOCTL=y +CONFIG_NETDEV_CAN_IOCTL=y CONFIG_NETDEV_IFINDEX=y CONFIG_NETDEV_LATEINIT=y CONFIG_NET_CAN=y diff --git a/boards/arm/stm32h7/nucleo-h753zi/configs/socketcan/defconfig b/boards/arm/stm32h7/nucleo-h753zi/configs/socketcan/defconfig index f9643ef1a1a8f..61cc0fe7c178b 100644 --- a/boards/arm/stm32h7/nucleo-h753zi/configs/socketcan/defconfig +++ b/boards/arm/stm32h7/nucleo-h753zi/configs/socketcan/defconfig @@ -40,7 +40,7 @@ CONFIG_INTELHEX_BINARY=y CONFIG_LINE_MAX=64 CONFIG_MM_REGIONS=4 CONFIG_NET=y -CONFIG_NETDEV_CAN_BITRATE_IOCTL=y +CONFIG_NETDEV_CAN_IOCTL=y CONFIG_NETDEV_IFINDEX=y CONFIG_NETDEV_LATEINIT=y CONFIG_NET_CAN=y diff --git a/boards/sim/sim/sim/configs/dynconns/defconfig b/boards/sim/sim/sim/configs/dynconns/defconfig index c009442b847d6..df646edceb3a0 100644 --- a/boards/sim/sim/sim/configs/dynconns/defconfig +++ b/boards/sim/sim/sim/configs/dynconns/defconfig @@ -35,8 +35,7 @@ CONFIG_MM_FILL_ALLOCATIONS=y CONFIG_NAME_MAX=64 CONFIG_NET=y CONFIG_NETDB_DNSCLIENT=y -CONFIG_NETDEV_CAN_BITRATE_IOCTL=y -CONFIG_NETDEV_CAN_FILTER_IOCTL=y +CONFIG_NETDEV_CAN_IOCTL=y CONFIG_NETDEV_LATEINIT=y CONFIG_NETDEV_PHY_IOCTL=y CONFIG_NETDOWN_NOTIFIER=y diff --git a/include/net/if.h b/include/net/if.h index db49af71b25ae..3f7174e46b9c1 100644 --- a/include/net/if.h +++ b/include/net/if.h @@ -237,6 +237,25 @@ struct can_ioctl_state_s enum can_ioctl_state_e state; }; +/* Fault confinement and error counters, SIOCGCANERRORS ioctl command. + * WARNING is error-active with either error counter at or above 96; + * PASSIVE and BUSOFF follow the controller's own state. + */ + +#define CAN_ERRSTATE_ACTIVE 0 +#define CAN_ERRSTATE_WARNING 1 +#define CAN_ERRSTATE_PASSIVE 2 +#define CAN_ERRSTATE_BUSOFF 3 + +struct can_ioctl_errors_s +{ + uint8_t state; /* CAN_ERRSTATE_* */ + uint8_t txerr; /* Transmit error counter (TEC) */ + uint8_t rxerr; /* Receive error counter (REC) */ + uint32_t errors; /* Bus errors observed since ifup, monotonic */ + uint32_t rx_overruns; /* RX frames the controller overwrote unread */ +}; + /* There are two forms of the I/F request structure. * One for IPv6 and one for IPv4. * Notice that they are (and must be) cast compatible and really different @@ -264,6 +283,7 @@ struct lifreq struct can_ioctl_data_s lifru_can_data; /* CAN bitrate request data */ struct can_ioctl_filter_s lifru_can_filter; /* CAN filter request data */ struct can_ioctl_state_s lifru_can_state; /* CAN/LIN controller state */ + struct can_ioctl_errors_s lifru_can_errors; /* CAN error counters */ } lifr_ifru; }; @@ -322,6 +342,7 @@ struct ifreq struct can_ioctl_data_s ifru_can_data; /* CAN bitrate request data */ struct can_ioctl_filter_s ifru_can_filter; /* CAN filter request data */ struct can_ioctl_state_s ifru_can_state; /* CAN/LIN controller state */ + struct can_ioctl_errors_s ifru_can_errors; /* CAN error counters */ FAR void *ifru_data; /* For use by interface */ } ifr_ifru; }; diff --git a/include/nuttx/net/ioctl.h b/include/nuttx/net/ioctl.h index 75bf689f9d565..b1519dddff570 100644 --- a/include/nuttx/net/ioctl.h +++ b/include/nuttx/net/ioctl.h @@ -127,6 +127,8 @@ #define SIOCCANRECOVERY _SIOC(0x0032) /* Recovery can, work only when bus-off state */ #define SIOCGCANSTATE _SIOC(0x0041) /* Get state from a CAN/LIN controller */ #define SIOCSCANSTATE _SIOC(0x0042) /* Set the LIN/CAN controller state */ +#define SIOCGCANERRORS _SIOC(0x0045) /* Get CAN error counters and fault + * confinement state */ /* Network socket control ***************************************************/ diff --git a/net/can/can_callback.c b/net/can/can_callback.c index 323e93893a0c0..b06302e0e6c14 100644 --- a/net/can/can_callback.c +++ b/net/can/can_callback.c @@ -92,6 +92,7 @@ can_data_event(FAR struct net_driver_s *dev, FAR struct can_conn_s *conn, #ifdef CONFIG_NET_STATISTICS g_netstats.can.drop++; #endif + NETDEV_RXDROPPED(dev); } /* In any event, the new data has now been handled */ @@ -126,28 +127,28 @@ uint32_t can_callback(FAR struct net_driver_s *dev, if (conn) { #ifdef CONFIG_NET_TIMESTAMP - /* TIMESTAMP sockopt is activated, - * create timestamp and copy to iob - */ + /* TIMESTAMP sockopt is activated, + * create timestamp and copy to iob + */ + + if (_SO_GETOPT(conn->sconn.s_options, SO_TIMESTAMP) && + (dev->d_iob != NULL)) + { + struct timeval tv; + FAR struct timespec *ts = (FAR struct timespec *)&tv; + int len; - if (_SO_GETOPT(conn->sconn.s_options, SO_TIMESTAMP) && - (dev->d_iob != NULL)) + clock_systime_timespec(ts); + tv.tv_usec = ts->tv_nsec / 1000; + + len = iob_trycopyin(dev->d_iob, (FAR uint8_t *)&tv, + sizeof(struct timeval), + -CONFIG_NET_LL_GUARDSIZE, false); + if (len == sizeof(struct timeval)) { - struct timeval tv; - FAR struct timespec *ts = (FAR struct timespec *)&tv; - int len; - - clock_systime_timespec(ts); - tv.tv_usec = ts->tv_nsec / 1000; - - len = iob_trycopyin(dev->d_iob, (FAR uint8_t *)&tv, - sizeof(struct timeval), - -CONFIG_NET_LL_GUARDSIZE, false); - if (len == sizeof(struct timeval)) - { - dev->d_len += len; - } + dev->d_len += len; } + } #endif conn_lock(&conn->sconn); diff --git a/net/netdev/Kconfig b/net/netdev/Kconfig index 227b5c2d58f54..a040c471c2ca9 100644 --- a/net/netdev/Kconfig +++ b/net/netdev/Kconfig @@ -16,31 +16,16 @@ config NETDEV_PHY_IOCTL ---help--- Enable support for ioctl() commands to access PHY registers -config NETDEV_CAN_BITRATE_IOCTL - bool "Enable CAN bitrate ioctl()" +config NETDEV_CAN_IOCTL + bool "Enable CAN ioctl()" default n select NETDEV_IOCTL depends on NET_CAN ---help--- - Enable support for ioctl() commands to change CAN bitrate - -config NETDEV_CAN_FILTER_IOCTL - bool "Enable CAN filter ioctl()" - default n - select NETDEV_IOCTL - depends on NET_CAN - ---help--- - Enable support for ioctl() commands to add/remove CAN hardware-level - filters (NOTE: Not supported by all drivers) - -config NETDEV_CAN_STATE_IOCTL - bool "Enable CAN state ioctl()" - default n - select NETDEV_IOCTL - depends on NET_CAN - ---help--- - Enable support for ioctl() commands to set/see CAN or LIN controller-state - (NOTE: Not supported by all drivers) + Enable support for the CAN network device ioctl() commands: + bitrate, hardware-level filters, CAN/LIN controller state and + error counters + (NOTE: Not every command is supported by every driver) config NETDEV_WIRELESS_IOCTL bool "Enable Wireless ioctl()" diff --git a/net/netdev/netdev_ioctl.c b/net/netdev/netdev_ioctl.c index 038ca7f1a5d54..4f6610f43963a 100644 --- a/net/netdev/netdev_ioctl.c +++ b/net/netdev/netdev_ioctl.c @@ -270,6 +270,7 @@ static void ioctl_get_ipv4addr(FAR struct sockaddr *outaddr, in_addr_t inaddr) { FAR struct sockaddr_in *dest = (FAR struct sockaddr_in *)outaddr; + dest->sin_family = AF_INET; dest->sin_port = 0; dest->sin_addr.s_addr = inaddr; @@ -295,6 +296,7 @@ static void ioctl_get_ipv4broadcast(FAR struct sockaddr *outaddr, in_addr_t inaddr, in_addr_t netmask) { FAR struct sockaddr_in *dest = (FAR struct sockaddr_in *)outaddr; + dest->sin_family = AF_INET; dest->sin_port = 0; dest->sin_addr.s_addr = net_ipv4addr_broadcast(inaddr, netmask); @@ -319,6 +321,7 @@ static void ioctl_get_ipv6addr(FAR struct sockaddr_storage *outaddr, FAR const net_ipv6addr_t inaddr) { FAR struct sockaddr_in6 *dest = (FAR struct sockaddr_in6 *)outaddr; + dest->sin6_family = AF_INET6; dest->sin6_port = 0; memcpy(dest->sin6_addr.in6_u.u6_addr8, inaddr, 16); @@ -343,6 +346,7 @@ static void ioctl_set_ipv4addr(FAR in_addr_t *outaddr, FAR const struct sockaddr *inaddr) { FAR const struct sockaddr_in *src = (FAR const struct sockaddr_in *)inaddr; + *outaddr = src->sin_addr.s_addr; } #endif @@ -366,6 +370,7 @@ static void ioctl_set_ipv6addr(FAR net_ipv6addr_t outaddr, { FAR const struct sockaddr_in6 *src = (FAR const struct sockaddr_in6 *)inaddr; + memcpy(outaddr, src->sin6_addr.in6_u.u6_addr8, 16); } #endif @@ -775,6 +780,7 @@ static ssize_t net_ioctl_ifreq_arglen(uint8_t domain, int cmd) case SIOCCANRECOVERY: case SIOCGCANSTATE: case SIOCSCANSTATE: + case SIOCGCANERRORS: case SIOCSIFNAME: case SIOCGIFNAME: case SIOCGIFINDEX: @@ -853,6 +859,7 @@ static int netdev_ifr_ioctl(FAR struct socket *psock, int cmd, case SIOCSIFNAME: /* Set interface name */ { FAR struct net_driver_s *tmpdev; + tmpdev = netdev_findbyindex(req->ifr_ifindex); if (tmpdev != NULL) { @@ -868,6 +875,7 @@ static int netdev_ifr_ioctl(FAR struct socket *psock, int cmd, case SIOCGIFNAME: /* Get interface name */ { FAR struct net_driver_s *tmpdev; + tmpdev = netdev_findbyindex(req->ifr_ifindex); if (tmpdev != NULL) { @@ -897,6 +905,7 @@ static int netdev_ifr_ioctl(FAR struct socket *psock, int cmd, == (ssize_t)sizeof(struct in6_ifreq)) { FAR struct in6_ifreq *ifr6 = (FAR struct in6_ifreq *)req; + dev = netdev_findbyindex(ifr6->ifr6_ifindex); } @@ -953,6 +962,7 @@ static int netdev_ifr_ioctl(FAR struct socket *psock, int cmd, case SIOCGLIFADDR: /* Get IP address */ { FAR struct lifreq *lreq = (FAR struct lifreq *)req; + idx = MIN(idx, CONFIG_NETDEV_MAX_IPv6_ADDR - 1); ioctl_get_ipv6addr(&lreq->lifr_addr, dev->d_ipv6[idx].addr); } @@ -961,6 +971,7 @@ static int netdev_ifr_ioctl(FAR struct socket *psock, int cmd, case SIOCSLIFADDR: /* Set IP address */ { FAR struct lifreq *lreq = (FAR struct lifreq *)req; + idx = MIN(idx, CONFIG_NETDEV_MAX_IPv6_ADDR - 1); netdev_ipv6_removemcastmac(dev, dev->d_ipv6[idx].addr); @@ -975,6 +986,7 @@ static int netdev_ifr_ioctl(FAR struct socket *psock, int cmd, case SIOCGLIFDSTADDR: /* Get P-to-P address */ { FAR struct lifreq *lreq = (FAR struct lifreq *)req; + ioctl_get_ipv6addr(&lreq->lifr_dstaddr, dev->d_ipv6draddr); } break; @@ -982,6 +994,7 @@ static int netdev_ifr_ioctl(FAR struct socket *psock, int cmd, case SIOCSLIFDSTADDR: /* Set P-to-P address */ { FAR struct lifreq *lreq = (FAR struct lifreq *)req; + ioctl_set_ipv6addr(dev->d_ipv6draddr, &lreq->lifr_dstaddr); } break; @@ -994,6 +1007,7 @@ static int netdev_ifr_ioctl(FAR struct socket *psock, int cmd, case SIOCGLIFNETMASK: /* Get network mask */ { FAR struct lifreq *lreq = (FAR struct lifreq *)req; + idx = MIN(idx, CONFIG_NETDEV_MAX_IPv6_ADDR - 1); ioctl_get_ipv6addr(&lreq->lifr_addr, dev->d_ipv6[idx].mask); } @@ -1002,6 +1016,7 @@ static int netdev_ifr_ioctl(FAR struct socket *psock, int cmd, case SIOCSLIFNETMASK: /* Set network mask */ { FAR struct lifreq *lreq = (FAR struct lifreq *)req; + idx = MIN(idx, CONFIG_NETDEV_MAX_IPv6_ADDR - 1); ioctl_set_ipv6addr(dev->d_ipv6[idx].mask, &lreq->lifr_addr); } @@ -1175,6 +1190,7 @@ static int netdev_ifr_ioctl(FAR struct socket *psock, int cmd, if (psock->s_domain == PF_INET6) { FAR struct in6_ifreq *ifr6 = (FAR struct in6_ifreq *)req; + ret = netdev_ipv6_add(dev, ifr6->ifr6_addr.in6_u.u6_addr16, ifr6->ifr6_prefixlen); if (ret == OK) @@ -1200,6 +1216,7 @@ static int netdev_ifr_ioctl(FAR struct socket *psock, int cmd, if (psock->s_domain == PF_INET6) { FAR struct in6_ifreq *ifr6 = (FAR struct in6_ifreq *)req; + ret = netdev_ipv6_del(dev, ifr6->ifr6_addr.in6_u.u6_addr16, ifr6->ifr6_prefixlen); if (ret == OK) @@ -1218,6 +1235,7 @@ static int netdev_ifr_ioctl(FAR struct socket *psock, int cmd, { FAR struct mii_ioctl_notify_s *notify = &req->ifr_ifru.ifru_mii_notify; + ret = dev->d_ioctl(dev, cmd, (unsigned long)(uintptr_t)notify); } else @@ -1234,6 +1252,7 @@ static int netdev_ifr_ioctl(FAR struct socket *psock, int cmd, { FAR struct mii_ioctl_data_s *mii_data = &req->ifr_ifru.ifru_mii_data; + ret = dev->d_ioctl(dev, cmd, (unsigned long)(uintptr_t)mii_data); } @@ -1244,7 +1263,7 @@ static int netdev_ifr_ioctl(FAR struct socket *psock, int cmd, break; #endif -#if defined(CONFIG_NETDEV_IOCTL) && defined(CONFIG_NETDEV_CAN_BITRATE_IOCTL) +#if defined(CONFIG_NETDEV_IOCTL) && defined(CONFIG_NETDEV_CAN_IOCTL) case SIOCSCANBITRATE: /* Set bitrate of a CAN controller */ if (dev->d_flags & IFF_UP) { @@ -1254,52 +1273,25 @@ static int netdev_ifr_ioctl(FAR struct socket *psock, int cmd, break; } - /* If down, fall-through to common code in SIOCGCANBITRATE. */ - - case SIOCGCANBITRATE: /* Get bitrate from a CAN controller */ - if (dev->d_ioctl) - { - FAR struct can_ioctl_data_s *can_bitrate_data = - &req->ifr_ifru.ifru_can_data; - ret = dev->d_ioctl(dev, cmd, - (unsigned long)(uintptr_t)can_bitrate_data); - } - else - { - ret = -ENOSYS; - } - break; -#endif + /* If down, fall-through to the common CAN ioctl code. */ -#if defined(CONFIG_NETDEV_IOCTL) && defined(CONFIG_NETDEV_CAN_FILTER_IOCTL) + case SIOCGCANBITRATE: /* Get bitrate from a CAN controller */ case SIOCACANEXTFILTER: /* Add an extended-ID filter */ case SIOCDCANEXTFILTER: /* Delete an extended-ID filter */ case SIOCACANSTDFILTER: /* Add a standard-ID filter */ case SIOCDCANSTDFILTER: /* Delete a standard-ID filter */ case SIOCCANRECOVERY: /* Recovery can controller when bus-off */ + case SIOCGCANSTATE: /* Get state from a CAN/LIN controller */ + case SIOCSCANSTATE: /* Set the LIN/CAN controller state */ + case SIOCGCANERRORS: /* Get CAN error counters and state */ if (dev->d_ioctl) { - FAR struct can_ioctl_filter_s *can_filter = - &req->ifr_ifru.ifru_can_filter; - ret = dev->d_ioctl(dev, cmd, - (unsigned long)(uintptr_t)can_filter); - } - else - { - ret = -ENOSYS; - } - break; -#endif + /* Every CAN ioctl argument struct is a member of the + * ifr_ifru union, so cmd's struct is at its address. + */ -#if defined(CONFIG_NETDEV_IOCTL) && defined(CONFIG_NETDEV_CAN_STATE_IOCTL) - case SIOCGCANSTATE: /* Get state from a CAN/LIN controller */ - case SIOCSCANSTATE: /* Set the LIN/CAN controller state */ - if (dev->d_ioctl) - { - FAR struct can_ioctl_state_s *can_state = - &req->ifr_ifru.ifru_can_state; ret = dev->d_ioctl(dev, cmd, - (unsigned long)(uintptr_t)can_state); + (unsigned long)(uintptr_t)&req->ifr_ifru); } else { @@ -1740,7 +1732,7 @@ static int netdev_ioctl(FAR struct socket *psock, int cmd, break; - default: + default: break; }