From e7ad870f18ec5b0a14052c99fa9414dab35b2278 Mon Sep 17 00:00:00 2001 From: haitomatic Date: Fri, 17 Oct 2025 06:09:40 +0000 Subject: [PATCH] arch/risc-v/mpfs: Add MSS CAN driver. Refactor to become lower half driver. Signed-off-by: Hai To --- .../risc-v/mpfs/boards/icicle/index.rst | 1 + arch/risc-v/src/mpfs/mpfs_can.c | 1099 ++++++----------- .../mpfs/icicle/configs/hwtest/defconfig | 1 - 3 files changed, 355 insertions(+), 746 deletions(-) diff --git a/Documentation/platforms/risc-v/mpfs/boards/icicle/index.rst b/Documentation/platforms/risc-v/mpfs/boards/icicle/index.rst index 1b0811d1469..b66ea75ae23 100644 --- a/Documentation/platforms/risc-v/mpfs/boards/icicle/index.rst +++ b/Documentation/platforms/risc-v/mpfs/boards/icicle/index.rst @@ -84,6 +84,7 @@ The following peripherals are configured: - UART0-4 - CorePWM (nb. needs the FPGA IP installed to work) - CoreSPI (nb. needs the FPGA IP installed to work) +- CAN0 & CAN1 (work with flat mode but there is still rare frame corruption issue in protected mode) The following applications are available: - TelnetD (at address 10.0.0.2) diff --git a/arch/risc-v/src/mpfs/mpfs_can.c b/arch/risc-v/src/mpfs/mpfs_can.c index 31ac5a20a74..7a113c3ed3b 100644 --- a/arch/risc-v/src/mpfs/mpfs_can.c +++ b/arch/risc-v/src/mpfs/mpfs_can.c @@ -40,11 +40,9 @@ #include #include #include -#include #include -#include +#include #include -#include #include @@ -65,15 +63,6 @@ #define CAN0_BASE MPFS_CAN0_LO_BASE #define CAN1_BASE MPFS_CAN1_LO_BASE -/* High level driver operational configuration */ - -#define CANWORK HPWORK - -/* For allocating the tx and rx CAN frame buffer */ - -#define POOL_SIZE 1 -#define TIMESTAMP_SIZE sizeof(struct timeval) /* support timestamping frame */ - /* MSS CAN TX/RX buffer configuration */ #define CAN_RX_BUFFER 32 @@ -272,7 +261,7 @@ * Utility definitions ****************************************************************************/ -#ifdef CONFIG_DEBUG_CAN_INFO +#ifdef CONFIG_DEBUG_NET_INFO static inline void print_uint32_t(const char *prefix, uint32_t val) { /* prefix + " 0b" + 32 bits + null terminator */ @@ -284,7 +273,7 @@ static inline void print_uint32_t(const char *prefix, uint32_t val) { sprintf(binary_str + strlen(binary_str), "%d", (val >> i) & 1); } - caninfo("%s", binary_str); + ninfo("%s", binary_str); } #endif @@ -409,7 +398,6 @@ struct mpfs_can_device_stats_s volatile uint32_t crc_errors; /* CRC errors count */ volatile uint32_t stuck_at_0; /* Stuck at 0 errors count */ volatile uint32_t restarts; /* CAN controller re-starts count */ - volatile uint32_t txb_sent; /* Tx messages sent count */ }; typedef struct mpfs_can_device_stats_s mpfs_can_device_stats_t; @@ -423,6 +411,8 @@ typedef struct mpfs_can_device_stats_s mpfs_can_device_stats_t; struct mpfs_can_instance_s { + struct netdev_lowerhalf_s dev; /* Lower-half network driver interface */ + uintptr_t reg_base; /* Pointer to CAN base register address */ uint32_t bitrate_value; /* The numerical bitrate value in bit/s */ @@ -446,25 +436,12 @@ struct mpfs_can_instance_s uint8_t basic_can_rxb_count; /* number of rx buffers */ uint8_t basic_can_txb_count; /* number of tx buffers */ - /* Frame descriptors */ - - struct can_frame *txdesc; /* Pointer to the transmit frame descriptor. */ - struct can_frame *rxdesc; /* Pointer to the receive frame descriptor. */ - /* MSS CAN composite message objects */ mpfs_can_msgobject_t *tx_msg; /* Pointer to the transmit message object */ mpfs_can_msgobject_t *rx_msg; /* Pointer to the receive message object */ - /* Work queue entries */ - - struct work_s rxwork; /* for deferring rx interrupt work to the wq */ - struct work_s txdwork; /* For deferring tx done interrupt work to the wq */ - struct work_s pollwork; /* For deferring poll work to the wq */ - mpfs_can_filterobject_t filter; /* hardware and software filters */ - - struct net_driver_s dev; /* Interface understood by the Nuttx network */ }; typedef struct mpfs_can_instance_s mpfs_can_instance_t; @@ -473,24 +450,12 @@ typedef struct mpfs_can_instance_s mpfs_can_instance_t; #ifdef CONFIG_MPFS_MSS_CAN0 static mpfs_can_instance_t g_can0; - -static uint8_t g_tx_pool0[(sizeof(struct can_frame) + TIMESTAMP_SIZE) * - POOL_SIZE] aligned_data(sizeof(uint32_t)); -static uint8_t g_rx_pool0[(sizeof(struct can_frame) + TIMESTAMP_SIZE) * - POOL_SIZE] aligned_data(sizeof(uint32_t)); - static mpfs_can_msgobject_t g_tx_msg0; static mpfs_can_msgobject_t g_rx_msg0; #endif #ifdef CONFIG_MPFS_MSS_CAN1 static mpfs_can_instance_t g_can1; - -static uint8_t g_tx_pool1[(sizeof(struct can_frame) + TIMESTAMP_SIZE) * - POOL_SIZE] aligned_data(sizeof(uint32_t)); -static uint8_t g_rx_pool1[(sizeof(struct can_frame) + TIMESTAMP_SIZE) * - POOL_SIZE] aligned_data(sizeof(uint32_t)); - static mpfs_can_msgobject_t g_tx_msg1; static mpfs_can_msgobject_t g_rx_msg1; #endif @@ -499,23 +464,6 @@ static mpfs_can_msgobject_t g_rx_msg1; * Private Function Prototypes ****************************************************************************/ -/* (from interrupt) High-level RX related functions */ - -static bool mpfs_can_retrieve_rx_frame(mpfs_can_instance_t *priv, - struct can_frame *cf); -static void mpfs_receive_work(void *arg); - -/* (from interrupt) High-level TX related functions */ - -static void mpfs_txdone_work(void *arg); - -/* High-level periodical TX related functions */ - -static int mpfs_transmit(mpfs_can_instance_t *priv); -static int mpfs_txpoll(struct net_driver_s *dev); -static void mpfs_txavail_work(void *arg); -static int mpfs_txavail(struct net_driver_s *dev); - /* (from interrupt) High-level error handling related functions */ static void mpfs_err_interrupt(mpfs_can_instance_t *priv, uint32_t isr); @@ -542,7 +490,7 @@ static void mpfs_can_reset(mpfs_can_instance_t *priv); static void mpfs_can_set_mode(mpfs_can_instance_t *priv, mpfs_can_mode_t mode); -#ifdef CONFIG_DEBUG_CAN_INFO +#ifdef CONFIG_DEBUG_NET_INFO static inline uint32_t mpfs_can_get_can_command_reg(mpfs_can_instance_t *priv); @@ -560,7 +508,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); -#ifdef CONFIG_DEBUG_CAN_INFO +#ifdef CONFIG_DEBUG_NET_INFO static void mpfs_can_print_status (mpfs_can_instance_t *priv); #endif @@ -575,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_CAN_INFO) || defined(CONFIG_NETDEV_CAN_BITRATE_IOCTL) +#if defined(CONFIG_DEBUG_NET_INFO) || defined(CONFIG_NETDEV_CAN_BITRATE_IOCTL) static uint32_t mpfs_can_get_sample_point(mpfs_can_instance_t *priv); #endif @@ -587,420 +535,308 @@ static uint8_t mpfs_can_config_buffer_n(mpfs_can_instance_t *priv, uint8_t buffer_number, mpfs_can_rxmsgobject_t *pmsg); -static uint8_t mpfs_can_get_message(mpfs_can_instance_t *priv); - -#ifdef CONFIG_DEBUG_CAN_INFO +#ifdef CONFIG_DEBUG_NET_INFO static inline uint32_t mpfs_can_get_rx_buffer_status(mpfs_can_instance_t *priv); #endif static uint32_t mpfs_can_get_rx_error_count(mpfs_can_instance_t *priv); -#ifdef CONFIG_DEBUG_CAN_INFO +#ifdef CONFIG_DEBUG_NET_INFO static inline bool mpfs_can_get_rx_gte96(mpfs_can_instance_t *priv); #endif /* CAN message TX buffer setter/getter functions */ -static uint8_t mpfs_can_send_message_ready(mpfs_can_instance_t *priv); -static uint8_t mpfs_can_send_message(mpfs_can_instance_t *priv); static uint8_t mpfs_can_send_message_abort(mpfs_can_instance_t *priv); 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); -#ifdef CONFIG_DEBUG_CAN_INFO +#ifdef CONFIG_DEBUG_NET_INFO static inline bool mpfs_can_get_tx_gte96(mpfs_can_instance_t *priv); #endif -/* Driver interface to Nuttx network callbacks */ +/* Lower-half driver interface functions */ -static int mpfs_ifup(struct net_driver_s *dev); -static int mpfs_ifdown(struct net_driver_s *dev); -#ifdef CONFIG_NETDEV_CAN_BITRATE_IOCTL -static int mpfs_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg); +static int mpfs_ifup(struct netdev_lowerhalf_s *dev); +static int mpfs_ifdown(struct netdev_lowerhalf_s *dev); +static int mpfs_transmit(struct netdev_lowerhalf_s *dev, + netpkt_t *pkt); +static netpkt_t *mpfs_receive(struct netdev_lowerhalf_s *dev); +#ifdef CONFIG_NETDEV_IOCTL +static int mpfs_ioctl(struct netdev_lowerhalf_s *dev, int cmd, + unsigned long arg); #endif +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* Lower-half driver operations */ + +static const struct netdev_ops_s g_netdev_ops = +{ + mpfs_ifup, /* ifup */ + mpfs_ifdown, /* ifdown */ + mpfs_transmit, /* transmit */ + mpfs_receive, /* receive */ +#ifdef CONFIG_NET_MCASTGROUP + NULL, /* addmac */ + NULL, /* rmmac */ +#endif +#ifdef CONFIG_NETDEV_IOCTL + mpfs_ioctl, /* ioctl */ +#else + NULL, /* ioctl */ +#endif + NULL /* reclaim */ +}; + /**************************************************************************** * Private Functions ****************************************************************************/ /**************************************************************************** - * Name: mpfs_can_retrieve_rx_frame + * Name: mpfs_receive * * Description: - * Retrieve CAN 2.0B frame from RX Buffer + * Receive a packet from the hardware. Called by upper-half driver. * * Input Parameters: - * priv - Pointer to the private CAN driver state structure - * cf - Pointer to CAN frame structure + * dev - Reference to the NuttX lower-half driver state structure * * Returned Value: - * This function returns CAN_OK on successful retrieval of CAN frame else - * it returns CAN_ERR - * - * Assumptions: - * Frame format word is already parsed in advance and provided as 'ffw' arg + * The received packet, or NULL if no packet is available * ****************************************************************************/ -static bool mpfs_can_retrieve_rx_frame(mpfs_can_instance_t *priv, - struct can_frame *cf) +static netpkt_t *mpfs_receive(struct netdev_lowerhalf_s *dev) { - uint8_t dlc; - bool ide; - bool rtr; - mpfs_can_msgobject_t *pmsg = priv->rx_msg; + mpfs_can_instance_t *priv = (mpfs_can_instance_t *)dev; + netpkt_t *pkt = NULL; + struct can_frame cf; + uint8_t buffer_number; + uintptr_t addr; + uint32_t reg; + uint32_t msg_id; + uint32_t msg_ctrl; + uint32_t data_high; + uint32_t data_low; - /* CAN ID & EFF & RTR Flags */ + /* Check if we have RX buffers configured */ - ide = (bool)(pmsg->msg_ctrl & MPFS_CAN_RX_MSG_CTRL_CMD_IDE); - rtr = (bool)(pmsg->msg_ctrl & MPFS_CAN_RX_MSG_CTRL_CMD_RTR); - cf->can_id = mpfs_can_msgid_to_canid(pmsg->id, ide, rtr); - - /* DLC */ - - dlc = (pmsg->msg_ctrl & MPFS_CAN_RX_MSG_CTRL_CMD_DLC) - >> MPFS_CAN_RX_MSG_CTRL_CMD_DLC_SHIFT; - if (dlc <= 8) + if (priv->basic_can_rxb_count == 0) { - cf->can_dlc = dlc; - } - else - { - canerr("DLC = %d is out of range\n", dlc); - return CAN_ERR; + return NULL; } - /* Data (big endian) */ + /* Find next RX buffer that has a message available */ - *(uint32_t *)&cf->data[0] = __builtin_bswap32(pmsg->data_high); - *(uint32_t *)&cf->data[4] = __builtin_bswap32(pmsg->data_low); - - return CAN_OK; -} - -/**************************************************************************** - * Name: mpfs_receive_work - * - * Description: - * An interrupt was received indicating the availability of a new RX packet - * - * Input Parameters: - * priv - Pointer to the private CAN driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * Global interrupts are disabled by interrupt handling logic. - * - ****************************************************************************/ - -static void mpfs_receive_work(void *arg) -{ - mpfs_can_instance_t *priv = (mpfs_can_instance_t *)arg; - - caninfo("CAN RX interrupt received\n"); - - while (CAN_VALID_MSG == mpfs_can_get_message(priv)) + for (buffer_number = CAN_RX_BUFFER - priv->basic_can_rxb_count; + buffer_number < CAN_RX_BUFFER; buffer_number++) { - struct can_frame *cf = (struct can_frame *)priv->rxdesc; + addr = priv->reg_base + MPFS_CAN_RX_MSG_OFFSET + + MPFS_CAN_RX_MSG_TOTAL_SIZE * buffer_number; - /* Retrieve the CAN 2.0B frame */ + /* Check if there is a valid message */ - if (CAN_OK != mpfs_can_retrieve_rx_frame(priv, cf)) + reg = getreg32(addr + MPFS_CAN_RX_MSG_CTRL_CMD_SHIFT); + + if (reg & MPFS_CAN_RX_MSG_CTRL_CMD_MSGAV_RTRS) { - /* Didn't receive full frame or message got filtered out */ + /* Read message directly from hardware buffer */ - continue; + msg_id = getreg32(addr + MPFS_CAN_RX_MSG_ID_SHIFT) + >> MPFS_CAN_MSG_ID_SHIFT; + data_low = getreg32(addr + MPFS_CAN_RX_MSG_DATA_LOW_SHIFT); + data_high = getreg32(addr + MPFS_CAN_RX_MSG_DATA_HIGH_SHIFT); + msg_ctrl = getreg32(addr + MPFS_CAN_RX_MSG_CTRL_CMD_SHIFT); + + /* Convert to CAN frame structure */ + + bool ide = (msg_ctrl & MPFS_CAN_RX_MSG_CTRL_CMD_IDE) != 0; + bool rtr = (msg_ctrl & MPFS_CAN_RX_MSG_CTRL_CMD_RTR) != 0; + + cf.can_id = mpfs_can_msgid_to_canid(msg_id, ide, rtr); + cf.can_dlc = (msg_ctrl & MPFS_CAN_RX_MSG_CTRL_CMD_DLC) + >> MPFS_CAN_RX_MSG_CTRL_CMD_DLC_SHIFT; + + /* Extract data bytes (swapped) */ + + *(uint32_t *)&cf.data[0] = __builtin_bswap32(data_high); + *(uint32_t *)&cf.data[4] = __builtin_bswap32(data_low); + + /* Acknowledge message removal from FIFO */ + + putreg32(msg_ctrl | MPFS_CAN_RX_MSG_CTRL_CMD_MSGAV_RTRS, + addr + MPFS_CAN_RX_MSG_CTRL_CMD_SHIFT); + + /* Allocate packet buffer and copy frame */ + + pkt = netpkt_alloc(dev, NETPKT_RX); + if (pkt != NULL) + { + netpkt_copyin(dev, pkt, (uint8_t *)&cf, + sizeof(struct can_frame), 0); + } + + ninfo("Received CAN message (ID: 0x%X, DLC: %d) " + "from buffer %d\n", + cf.can_id & CAN_EFF_MASK, cf.can_dlc, buffer_number); + break; } - - /* Lock the network; we have to protect the dev.d_len, dev.d_buf - * and dev.d_iob from the devif_poll path - */ - - net_lock(); - - /* Copy the buffer pointer to priv->dev.d_buf Set amount of data - * in priv->dev.d_len - */ - - priv->dev.d_len = sizeof(struct can_frame); - priv->dev.d_buf = (uint8_t *)cf; - - /* Send to socket interface */ - - NETDEV_RXPACKETS(&priv->dev); - can_input(&priv->dev); - - net_unlock(); - - /* Point the packet buffer back to the next Tx buffer that will be - * used during the next write. If the write queue is full, then - * this will point at an active buffer, which must not be written - * to. This is OK because devif_poll won't be called unless the - * queue is not full. - */ - - priv->dev.d_buf = (uint8_t *)priv->txdesc; } - /* Check for RX FIFO Overflow */ - - if (MPFS_CAN_INT_STATUS_OVR_LOAD & priv->isr) - { - /* Re-enable RX overload err int as all the RX buffers are handled */ - - mpfs_can_set_int_ebl(priv, MPFS_CAN_INT_ENABLE_OVR_LOAD_INT_ENBL); - } - - /* Re-enable RX msg receive interrupt */ - - mpfs_can_set_int_ebl(priv, MPFS_CAN_INT_ENABLE_RX_MSG_INT_ENBL); -} - -/**************************************************************************** - * Name: mpfs_txdone_work - * - * Description: - * An interrupt was received indicating that the last TX packet(s) is done - * - * Input Parameters: - * priv - Pointer to the private CAN 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 mpfs_txdone_work(void *arg) -{ - mpfs_can_instance_t *priv = (mpfs_can_instance_t *)arg; - - caninfo("TX done interrupt received\n"); - - /* There should be space for a new TX in any event. Poll the network for - * new XMIT data - */ - - net_lock(); - devif_poll(&priv->dev, mpfs_txpoll); - net_unlock(); + return pkt; } /**************************************************************************** * Name: mpfs_transmit * * Description: - * Start hardware transmission. Called either from the txdone interrupt - * handling or from watchdog based polling. + * Transmit a packet using the hardware. Called by upper-half driver. * * Input Parameters: - * priv - Pointer to the private CAN driver state structure + * dev - Reference to the NuttX lower-half driver state structure + * pkt - The packet to transmit * * Returned Value: - * Zero (CAN_OK) on success; a negated errno on failure - * - * Assumptions: - * May or may not be called from an interrupt handler. In either case, - * global interrupts are disabled, either explicitly or indirectly through - * interrupt handling logic. + * Zero (OK) on success; a negated errno on failure * ****************************************************************************/ -static int mpfs_transmit(mpfs_can_instance_t *priv) +static int mpfs_transmit(struct netdev_lowerhalf_s *dev, + netpkt_t *pkt) { - uint8_t ret; + mpfs_can_instance_t *priv = (mpfs_can_instance_t *)dev; + struct can_frame cf; + uint8_t buffer_number; + uintptr_t addr; + uint32_t msg_ctrl; + uint32_t msg_id; + uint32_t data_high = 0; + uint32_t data_low = 0; - /* Retrieve the CAN 2.0B frame from network device buffer */ + /* Validate input parameters */ - struct can_frame *cf = (struct can_frame *)priv->dev.d_buf; - - /* Fill the CAN msg object to be sent */ - - mpfs_can_msgobject_t *pmsg = priv->tx_msg; - - /* CAN TX msg control command */ - - pmsg->msg_ctrl = ((cf->can_id & CAN_EFF_FLAG) ? - MPFS_CAN_TX_MSG_CTRL_CMD_IDE : 0) - | ((cf->can_dlc << MPFS_CAN_TX_MSG_CTRL_CMD_DLC_SHIFT) - & MPFS_CAN_TX_MSG_CTRL_CMD_DLC) - | ((cf->can_id & CAN_RTR_FLAG) ? - MPFS_CAN_TX_MSG_CTRL_CMD_RTR : 0); - - /* CAN ID */ - - pmsg->id = mpfs_can_canid_to_msgid(cf->can_id); - - /* CAN data */ - - if (!(pmsg->msg_ctrl & MPFS_CAN_TX_MSG_CTRL_CMD_RTR)) + if (dev == NULL || pkt == NULL) { - pmsg->data_high = __builtin_bswap32(*(uint32_t *)&cf->data[0]); - pmsg->data_low = __builtin_bswap32(*(uint32_t *)&cf->data[4]); - } - - /* Insert CAN msg object into available TX bf */ - - if (CAN_VALID_MSG != (ret = mpfs_can_send_message(priv))) - { - canerr("Failed to send CAN frame due to %s\n", - ret == CAN_INVALID_BUFFER ? "invalid buffer" : - ret == CAN_NO_MSG ? "no TX buffer available" : "unknown err"); - return CAN_ERR; - } - - /* Increment statistics */ - - priv->stats.txb_sent++; - NETDEV_TXPACKETS(&priv->dev); - - caninfo("Single CAN message transmit done\n"); - - return CAN_OK; -} - -/**************************************************************************** - * Name: mpfs_txpoll - * - * Description: - * The transmitter is available, check if the network has any outgoing - * packets ready to send. This is a callback from devif_poll(). - * devif_poll() may be called: - * - * 1. When the preceding TX packet send is complete, - * 2. During normal TX polling - * - * Input Parameters: - * dev - Reference to the NuttX driver state structure - * - * Returned Value: - * Zero (CAN_OK) on success; a negated errno on failure - * - * Assumptions: - * May or may not be called from an interrupt handler. In either case, - * global interrupts are disabled, either explicitly or indirectly through - * interrupt handling logic. - * - ****************************************************************************/ - -static int mpfs_txpoll(struct net_driver_s *dev) -{ - mpfs_can_instance_t *priv = - (mpfs_can_instance_t *)dev->d_private; - - /* If the polling resulted in data that should be sent out on the network, - * the field d_len is set to a value > 0. - */ - - if (priv->dev.d_len > 0) - { - /* Send the packet. If failure, return a non-zero value to terminate - * the poll. - */ - - if (CAN_OK != mpfs_transmit(priv)) + nerr("Invalid parameters: dev=%p, pkt=%p\n", dev, pkt); + if (pkt != NULL) { - return -EBUSY; + netpkt_free(dev, pkt, NETPKT_TX); } - /* Check if there is room in the device to hold another packet. If - * not, return a non-zero value to terminate the poll. - */ + return -EINVAL; + } - if (CAN_OK != mpfs_can_send_message_ready(priv)) + /* Validate packet size first, like reference driver */ + + if (netpkt_getdatalen(dev, pkt) != sizeof(struct can_frame)) + { + nerr("Invalid packet size: %u bytes (expected %zu)\n", + netpkt_getdatalen(dev, pkt), sizeof(struct can_frame)); + netpkt_free(dev, pkt, NETPKT_TX); + return -EINVAL; + } + + /* Get direct pointer to CAN frame data */ + + struct can_frame *frame = + (struct can_frame *)netpkt_getdata(dev, pkt); + + if (frame == NULL) + { + nerr("Failed to get packet data pointer\n"); + netpkt_free(dev, pkt, NETPKT_TX); + return -EINVAL; + } + + /* Copy frame locally to avoid any pointer issues */ + + cf = *frame; + + /* Check if we have TX buffers available */ + + if (priv->basic_can_txb_count == 0) + { + nerr("No TX buffers configured\n"); + netpkt_free(dev, pkt, NETPKT_TX); + return -EINVAL; + } + + /* Find next available TX buffer */ + + for (buffer_number = CAN_TX_BUFFER - priv->basic_can_txb_count; + buffer_number < CAN_TX_BUFFER; buffer_number++) + { + /* Check if this transmit buffer is available (not busy) */ + + if ((mpfs_can_get_tx_buffer_status(priv) & (1 << buffer_number)) == 0) { - return -EBUSY; + /* Calculate hardware buffer address */ + + addr = priv->reg_base + MPFS_CAN_TX_MSG_OFFSET + + MPFS_CAN_TX_MSG_TOTAL_SIZE * buffer_number; + + /* Prepare control word */ + + msg_ctrl = ((cf.can_id & CAN_EFF_FLAG) ? + MPFS_CAN_TX_MSG_CTRL_CMD_IDE : 0) + | ((cf.can_dlc << MPFS_CAN_TX_MSG_CTRL_CMD_DLC_SHIFT) + & MPFS_CAN_TX_MSG_CTRL_CMD_DLC) + | ((cf.can_id & CAN_RTR_FLAG) ? + MPFS_CAN_TX_MSG_CTRL_CMD_RTR : 0); + + /* Prepare ID */ + + msg_id = mpfs_can_canid_to_msgid(cf.can_id); + + /* Prepare data (only if not RTR) */ + + if (!(msg_ctrl & MPFS_CAN_TX_MSG_CTRL_CMD_RTR)) + { + if (cf.can_dlc > 0) + { + data_high = __builtin_bswap32(*(uint32_t *)&cf.data[0]); + } + + if (cf.can_dlc > 4) + { + data_low = __builtin_bswap32(*(uint32_t *)&cf.data[4]); + } + } + + /* Write directly to hardware buffer */ + + putreg32(msg_id << MPFS_CAN_MSG_ID_SHIFT, + addr + MPFS_CAN_TX_MSG_ID_SHIFT); + putreg32(data_low, addr + MPFS_CAN_TX_MSG_DATA_LOW_SHIFT); + putreg32(data_high, addr + MPFS_CAN_TX_MSG_DATA_HIGH_SHIFT); + + /* Trigger transmission with control word */ + + putreg32(msg_ctrl + | MPFS_CAN_TX_MSG_CTRL_CMD_WPN_B + | MPFS_CAN_TX_MSG_CTRL_CMD_WPN_A + | MPFS_CAN_TX_MSG_CTRL_CMD_TX_INT_EBL + | MPFS_CAN_TX_MSG_CTRL_CMD_TX_REQ, + addr + MPFS_CAN_TX_MSG_CTRL_CMD_SHIFT); + + ninfo("Sending CAN message (ID: 0x%X, DLC: %d) via buffer %d\n", + cf.can_id & CAN_EFF_MASK, cf.can_dlc, buffer_number); + + netpkt_free(dev, pkt, NETPKT_TX); + return OK; } } - /* If zero is returned, the polling will continue until all connections - * have been examined. - */ + /* No available TX buffer found */ - return CAN_OK; -} - -/**************************************************************************** - * Name: mpfs_txavail_work - * - * Description: - * Perform an out-of-cycle poll on the worker thread. - * - * Input Parameters: - * arg - Reference to the NuttX driver state structure (cast to void*) - * - * Returned Value: - * None - * - * Assumptions: - * Called on the higher priority worker thread. - * - ****************************************************************************/ - -static void mpfs_txavail_work(void *arg) -{ - mpfs_can_instance_t *priv = (mpfs_can_instance_t *)arg; - - net_lock(); - - /* Ignore the notification if the interface is not yet up */ - - if (priv->bifup) - { - /* Check if there is room in the controller to hold another outgoing - * packet. - */ - - if (CAN_OK == mpfs_can_send_message_ready(priv)) - { - /* Yes, there is, poll the network for new TXT transmit */ - - devif_poll(&priv->dev, mpfs_txpoll); - } - } - - net_unlock(); -} - -/**************************************************************************** - * Name: mpfs_txavail - * - * Description: - * Driver callback invoked when new TX data is available. This is a - * stimulus perform an out-of-cycle poll and, thereby, reduce the TX - * latency. - * - * Input Parameters: - * dev - Reference to the NuttX driver state structure - * - * Returned Value: - * 0 - CAN_OK - * - * Assumptions: - * Called in normal user mode - * - ****************************************************************************/ - -static int mpfs_txavail(struct net_driver_s *dev) -{ - mpfs_can_instance_t *priv = - (mpfs_can_instance_t *)dev->d_private; - - if (work_available(&priv->pollwork)) - { - /* Schedule to serialize the poll on the worker thread. */ - - mpfs_txavail_work(priv); - } - - return CAN_OK; + nerr("No TX buffer available\n"); + netpkt_free(dev, pkt, NETPKT_TX); + return -EBUSY; } /**************************************************************************** @@ -1024,13 +860,13 @@ static void mpfs_err_interrupt(mpfs_can_instance_t *priv, uint32_t isr) if (MPFS_CAN_INT_STATUS_ARB_LOSS & isr) { - canwarn("Arbitration loss error interrupt\n"); + nwarn("Arbitration loss error interrupt\n"); priv->stats.arbitration_loss++; } if (MPFS_CAN_INT_STATUS_OVR_LOAD & isr) { - canwarn("RX overload error interrupt\n"); + nwarn("RX overload error interrupt\n"); priv->stats.rx_overload++; /* Mask the interrupt until it is handled in worker */ @@ -1039,42 +875,42 @@ static void mpfs_err_interrupt(mpfs_can_instance_t *priv, uint32_t isr) /* Notify to socket interface */ - NETDEV_RXERRORS(&priv->dev); + NETDEV_RXERRORS(&priv->dev.netdev); } if (MPFS_CAN_INT_STATUS_BIT_ERR & isr) { - canwarn("Bit error interrupt\n"); + nwarn("Bit error interrupt\n"); priv->stats.bit_errors++; } if (MPFS_CAN_INT_STATUS_STUFF_ERR & isr) { - canwarn("Stuffing error interrupt\n"); + nwarn("Stuffing error interrupt\n"); priv->stats.stuff_errors++; } if (MPFS_CAN_INT_STATUS_ACK_ERR & isr) { - canwarn("Ack error interrupt\n"); + nwarn("Ack error interrupt\n"); priv->stats.ack_errors++; } if (MPFS_CAN_INT_STATUS_FORM_ERR & isr) { - canwarn("Form error interrupt\n"); + nwarn("Form error interrupt\n"); priv->stats.form_errors++; } if (MPFS_CAN_INT_STATUS_CRC_ERR & isr) { - canwarn("CRC error interrupt\n"); + nwarn("CRC error interrupt\n"); priv->stats.crc_errors++; } if (MPFS_CAN_INT_STATUS_STUCK_AT_0 & isr) { - canwarn("Stuck at 0 error interrupt\n"); + nwarn("Stuck at 0 error interrupt\n"); priv->stats.stuck_at_0++; } @@ -1088,35 +924,35 @@ static void mpfs_err_interrupt(mpfs_can_instance_t *priv, uint32_t isr) if (priv->error_status == state) { - canwarn("No state change! Missed interrupt?\n"); + nwarn("No state change! Missed interrupt?\n"); } priv->error_status = state; if (state == 0) { - caninfo("Change to ERROR_ACTIVE error state\n"); + ninfo("Change to ERROR_ACTIVE error state\n"); return; } else if (state == 1) { priv->stats.error_passive++; - canwarn("Change to ERROR_PASSIVE error state\n"); + nwarn("Change to ERROR_PASSIVE error state\n"); } else if (state > 1) { priv->stats.bus_off++; - canwarn("Change to BUS_OFF error state\n"); + nwarn("Change to BUS_OFF error state\n"); } else { - canwarn("Unhandled error state %d\n", state); + nwarn("Unhandled error state %d\n", state); return; } /* Handle bus-off and error passive state */ - canwarn("Bus-off and Error passive handling: reset CAN controller..\n"); + nwarn("Bus-off and Error passive handling: reset CAN controller..\n"); /* Bring down the CAN interface */ @@ -1131,7 +967,7 @@ static void mpfs_err_interrupt(mpfs_can_instance_t *priv, uint32_t isr) if (CAN_OK != mpfs_can_set_bitrate(priv, priv->bitrate_value)) { - canerr("Failed to set bitrate\n"); + nerr("Failed to set bitrate\n"); } /* Configure CAN modes */ @@ -1142,7 +978,7 @@ static void mpfs_err_interrupt(mpfs_can_instance_t *priv, uint32_t isr) if (CAN_OK != mpfs_can_config_buffer(priv)) { - canerr("CAN RX buffer re-initialization failed\n"); + nerr("CAN RX buffer re-initialization failed\n"); } /* Bring up the CAN interface again */ @@ -1151,7 +987,7 @@ static void mpfs_err_interrupt(mpfs_can_instance_t *priv, uint32_t isr) /* Notify to socket interface. */ - NETDEV_ERRORS(&priv->dev); + NETDEV_ERRORS(&priv->dev.netdev); } /**************************************************************************** @@ -1184,20 +1020,22 @@ static int mpfs_interrupt(int irq, void *context, void *arg) if (priv->isr & MPFS_CAN_INT_STATUS_RX_MSG) { - /* Mask INT_RX_MSG until received message is handled be the worker */ + /* Notify the lower-half that data is ready for reception */ - mpfs_can_clear_int_ebl(priv, MPFS_CAN_INT_ENABLE_RX_MSG_INT_ENBL); + netdev_lower_rxready(&priv->dev); - work_queue(CANWORK, &priv->rxwork, mpfs_receive_work, priv, 0); + /* Re-enable RX message interrupt */ + + mpfs_can_set_int_ebl(priv, MPFS_CAN_INT_ENABLE_RX_MSG_INT_ENBL); } /* TX done interrupt */ if (priv->isr & MPFS_CAN_INT_STATUS_TX_MSG) { - /* Schedule work to poll for next available tx frame from the network */ + /* Notify the lower-half that transmission is complete */ - work_queue(CANWORK, &priv->txdwork, mpfs_txdone_work, priv, 0); + netdev_lower_txdone(&priv->dev); } /* Error interrupts */ @@ -1212,7 +1050,7 @@ static int mpfs_interrupt(int irq, void *context, void *arg) | MPFS_CAN_INT_STATUS_BUS_OFF | MPFS_CAN_INT_STATUS_STUCK_AT_0)) != 0) { - canerr("Some error interrupts..."); + nerr("Some error interrupts..."); mpfs_err_interrupt(priv, priv->isr); } @@ -1221,8 +1059,9 @@ static int mpfs_interrupt(int irq, void *context, void *arg) mpfs_can_clear_int_status(priv, priv->isr); - caninfo("Interrupt received\n"); -#ifdef CONFIG_DEBUG_CAN_INFO + /* ninfo("Interrupt received\n"); */ +#ifdef CONFIG_DEBUG_NET_INFO + return CAN_OK; mpfs_can_print_status(priv); #endif @@ -1264,7 +1103,7 @@ static uint8_t mpfs_can_add_filter(mpfs_can_instance_t *priv, { if (priv->filter.use_mask_filter) { - canwarn("Mask filter is already in use. Overwrite now\n"); + nwarn("Mask filter is already in use. Overwrite now\n"); } if (filter_id2 == CAN_SFF_MASK) @@ -1281,7 +1120,7 @@ static uint8_t mpfs_can_add_filter(mpfs_can_instance_t *priv, } else { - canerr("Invalid filter mask\n"); + nerr("Invalid filter mask\n"); return CAN_ERR; } @@ -1289,7 +1128,7 @@ static uint8_t mpfs_can_add_filter(mpfs_can_instance_t *priv, if (CAN_OK != (ret = mpfs_can_config_buffer(priv))) { - canerr("Failed to configure RX buffer:%d\n", ret); + nerr("Failed to configure RX buffer:%d\n", ret); return CAN_ERR; } @@ -1297,12 +1136,12 @@ static uint8_t mpfs_can_add_filter(mpfs_can_instance_t *priv, } else if (filter_type == CAN_FILTER_RANGE) { - canerr("Range filter type not supported\n"); + nerr("Range filter type not supported\n"); return CAN_ERR; } else { - canerr("Invalid filter type\n"); + nerr("Invalid filter type\n"); return CAN_ERR; } @@ -1343,7 +1182,7 @@ static uint8_t mpfs_can_reset_filter(mpfs_can_instance_t *priv) if (CAN_OK != (ret = mpfs_can_config_buffer(priv))) { - canerr("Failed to configure RX buffer:%d\n", ret); + nerr("Failed to configure RX buffer:%d\n", ret); return CAN_ERR; } @@ -1378,7 +1217,7 @@ static void mpfs_can_reset(mpfs_can_instance_t *priv) { /* Reset CAN controller 0 */ - caninfo("Resetting CAN controller 0\n"); + ninfo("Resetting CAN controller 0\n"); modifyreg32(MPFS_SYSREG_BASE + MPFS_SYSREG_SUBBLK_CLOCK_CR_OFFSET, 0, SYSREG_SUBBLK_CLOCK_CR_CAN0); @@ -1391,7 +1230,7 @@ static void mpfs_can_reset(mpfs_can_instance_t *priv) { /* Reset CAN controller 1 */ - caninfo("Resetting CAN controller 1\n"); + ninfo("Resetting CAN controller 1\n"); modifyreg32(MPFS_SYSREG_BASE + MPFS_SYSREG_SUBBLK_CLOCK_CR_OFFSET, 0, SYSREG_SUBBLK_CLOCK_CR_CAN1); @@ -1453,7 +1292,7 @@ static void mpfs_can_set_mode(mpfs_can_instance_t *priv, putreg32((uint32_t)mode, priv->reg_base + MPFS_CAN_CAN_COMMAND_OFFSET); } -#ifdef CONFIG_DEBUG_CAN_INFO +#ifdef CONFIG_DEBUG_NET_INFO /**************************************************************************** * Name: The mpfs_can_get_can_command_reg * @@ -1706,7 +1545,7 @@ static uint8_t mpfs_can_get_error_status(mpfs_can_instance_t *priv) return (uint8_t)reg; } -#ifdef CONFIG_DEBUG_CAN_INFO +#ifdef CONFIG_DEBUG_NET_INFO /**************************************************************************** * Name: mpfs_can_print_status * @@ -1726,39 +1565,38 @@ static uint8_t mpfs_can_get_error_status(mpfs_can_instance_t *priv) static void mpfs_can_print_status(mpfs_can_instance_t *priv) { - caninfo("========================================================\n"); - caninfo(">> CAN Settings:\n"); - caninfo(" Bitrate: %u\n", priv->bitrate_value); - caninfo(" Sample point: %u\n", mpfs_can_get_sample_point(priv)); + ninfo("========================================================\n"); + ninfo(">> CAN Settings:\n"); + ninfo(" Bitrate: %u\n", priv->bitrate_value); + ninfo(" Sample point: %u\n", mpfs_can_get_sample_point(priv)); print_uint32_t(" Cfg: ", mpfs_can_get_can_config_reg(priv)); print_uint32_t(" Cmd: ", mpfs_can_get_can_command_reg(priv)); print_uint32_t(" Interrupt Enabled: ", mpfs_can_get_int_ebl(priv)); - caninfo(">> CAN TX/RX buffer, Interrupt status:\n"); + ninfo(">> CAN TX/RX buffer, Interrupt status:\n"); print_uint32_t(" TX Buffer Status: ", mpfs_can_get_tx_buffer_status(priv)); print_uint32_t(" RX Buffer Status: ", mpfs_can_get_rx_buffer_status(priv)); print_uint32_t(" Interrupt status: ", priv->isr); - caninfo(">> CAN RX/TX Error Status:\n"); - caninfo(" Error State: %u\n", mpfs_can_get_error_status(priv)); - caninfo(" TX Error Count: %d\n", priv->tx_err_count); - caninfo(" RX Error Count: %d\n", priv->rx_err_count); - caninfo(" TX GTE 96: %s\n", mpfs_can_get_tx_gte96(priv) ? "Yes" : "No"); - caninfo(" RX GTE 96: %s\n", mpfs_can_get_rx_gte96(priv) ? "Yes" : "No"); - caninfo(">> CAN Stats:\n"); - caninfo(" Error Passive: %u\n", priv->stats.error_passive); - caninfo(" Bus Off: %u\n", priv->stats.bus_off); - caninfo(" Arbitration Loss: %u\n", priv->stats.arbitration_loss); - caninfo(" Rx Overload: %u\n", priv->stats.rx_overload); - caninfo(" Bit Errors: %u\n", priv->stats.bit_errors); - caninfo(" Stuff Errors: %u\n", priv->stats.stuff_errors); - caninfo(" Ack Errors: %u\n", priv->stats.ack_errors); - caninfo(" Form Errors: %u\n", priv->stats.form_errors); - caninfo(" CRC Errors: %u\n", priv->stats.crc_errors); - caninfo(" Stuck at 0: %u\n", priv->stats.stuck_at_0); - caninfo(" Restarts: %u\n", priv->stats.restarts); - caninfo(" TX message sent: %u\n", priv->stats.txb_sent); - caninfo("========================================================\n"); + ninfo(">> CAN RX/TX Error Status:\n"); + ninfo(" Error State: %u\n", mpfs_can_get_error_status(priv)); + ninfo(" TX Error Count: %d\n", priv->tx_err_count); + ninfo(" RX Error Count: %d\n", priv->rx_err_count); + ninfo(" TX GTE 96: %s\n", mpfs_can_get_tx_gte96(priv) ? "Yes" : "No"); + ninfo(" RX GTE 96: %s\n", mpfs_can_get_rx_gte96(priv) ? "Yes" : "No"); + ninfo(">> CAN Stats:\n"); + ninfo(" Error Passive: %u\n", priv->stats.error_passive); + ninfo(" Bus Off: %u\n", priv->stats.bus_off); + ninfo(" Arbitration Loss: %u\n", priv->stats.arbitration_loss); + ninfo(" Rx Overload: %u\n", priv->stats.rx_overload); + ninfo(" Bit Errors: %u\n", priv->stats.bit_errors); + ninfo(" Stuff Errors: %u\n", priv->stats.stuff_errors); + ninfo(" Ack Errors: %u\n", priv->stats.ack_errors); + ninfo(" Form Errors: %u\n", priv->stats.form_errors); + ninfo(" CRC Errors: %u\n", priv->stats.crc_errors); + ninfo(" Stuck at 0: %u\n", priv->stats.stuck_at_0); + ninfo(" Restarts: %u\n", priv->stats.restarts); + ninfo("========================================================\n"); } #endif @@ -1839,7 +1677,8 @@ static uint32_t mpfs_can_msgid_to_canid(uint32_t id, * Name: mpfs_can_set_bitrate * * Description: - * The mpfs_can_set_bitrate() function returns the current set bitrate + * The mpfs_can_set_bitrate() function sets the bitrate for the CAN + * controller * * Input Parameters: * priv - Pointer to the private CAN driver state structure @@ -1858,56 +1697,54 @@ static uint8_t mpfs_can_set_bitrate(mpfs_can_instance_t *priv, uint32_t bitrate) { uint32_t bitrate_constant; + switch (bitrate) { case 5000: - priv->bitrate_value = bitrate; bitrate_constant = CAN_SPEED_32M_5K; break; case 10000: - priv->bitrate_value = bitrate; bitrate_constant = CAN_SPEED_32M_10K; break; case 20000: - priv->bitrate_value = bitrate; bitrate_constant = CAN_SPEED_32M_20K; break; case 50000: - priv->bitrate_value = bitrate; bitrate_constant = CAN_SPEED_32M_50K; break; case 100000: - priv->bitrate_value = bitrate; bitrate_constant = CAN_SPEED_32M_100K; break; case 125000: - priv->bitrate_value = bitrate; bitrate_constant = CAN_SPEED_32M_125K; break; case 250000: - priv->bitrate_value = bitrate; bitrate_constant = CAN_SPEED_32M_250K; break; case 500000: - priv->bitrate_value = bitrate; bitrate_constant = CAN_SPEED_32M_500K; break; case 1000000: - priv->bitrate_value = bitrate; bitrate_constant = CAN_SPEED_32M_1M; break; default: - canerr("Invalid bitrate %u\n", bitrate); + nerr("Invalid bitrate %u\n", bitrate); return CAN_ERR; } bitrate_constant |= MPFS_CAN_CAN_CONFIG_AUTO_RESTART; putreg32(bitrate_constant , priv->reg_base + MPFS_CAN_CAN_CONFIG_OFFSET); + /* Store the bitrate value only after successful validation and + * configuration + */ + + priv->bitrate_value = bitrate; + return CAN_OK; } -#if defined(CONFIG_DEBUG_CAN_INFO) || defined(CONFIG_NETDEV_CAN_BITRATE_IOCTL) +#if defined(CONFIG_DEBUG_NET_INFO) || defined(CONFIG_NETDEV_CAN_BITRATE_IOCTL) /**************************************************************************** * Name: mpfs_can_get_sample_point * @@ -2071,95 +1908,7 @@ static uint8_t mpfs_can_config_buffer_n (mpfs_can_instance_t *priv, return CAN_OK; } -/**************************************************************************** - * Name: mpfs_can_get_message - * - * Description: - * The mpfs_can_get_message() function read message from the first buffer - * set for Basic CAN operation that contains a message. Once the message - * has been read from the buffer, the message receipt is acknowledged. - * Note: Since neither a hardware nor a software FIFO exists, message - * inversion - * might happen (example, a newer message might be read from the receive - * buffer prior to an older message) - * - * Input Parameters: - * priv - Pointer to the private CAN driver state structure - * - * Returned Value: - * This function returns CAN_VALID_MSG on successful execution, otherwise it - * will returns following error codes: - * - * | Constants | Description | - * |-----------------------|---------------------------------------------| - * | CAN_NO_MSG | Indicates that there is no message received | - * | CAN_INVALID_BUFFER | Indicates invalid buffer number | - * - * Assumptions: - * None - * - ****************************************************************************/ - -static uint8_t mpfs_can_get_message(mpfs_can_instance_t *priv) -{ - uint8_t success = CAN_NO_MSG; - uint8_t buffer_number; - mpfs_can_msgobject_t *pmsg = priv->rx_msg; - uintptr_t addr; - uint32_t reg; - - /* Is a buffer configured for Basic CAN? */ - - if (priv->basic_can_rxb_count == 0) - { - return CAN_INVALID_BUFFER; - } - - /* Find next BASIC CAN buffer that has a message available */ - - for (buffer_number = CAN_RX_BUFFER - priv->basic_can_rxb_count; - buffer_number < CAN_RX_BUFFER; buffer_number++) - { - addr = priv->reg_base + MPFS_CAN_RX_MSG_OFFSET - + MPFS_CAN_RX_MSG_TOTAL_SIZE * buffer_number; - - /* Check that if there is a valid message */ - - reg = getreg32(addr + MPFS_CAN_RX_MSG_CTRL_CMD_SHIFT); - - if (reg & MPFS_CAN_RX_MSG_CTRL_CMD_MSGAV_RTRS) - { - /* Copy ID */ - - pmsg->id = getreg32(addr + MPFS_CAN_RX_MSG_ID_SHIFT) - >> MPFS_CAN_MSG_ID_SHIFT; - - /* Copy 4 of the data bytes */ - - pmsg->data_low = getreg32(addr + MPFS_CAN_RX_MSG_DATA_LOW_SHIFT); - - /* Copy the other 4 data bytes */ - - pmsg->data_high = getreg32(addr + MPFS_CAN_RX_MSG_DATA_HIGH_SHIFT); - - /* Get DLC, IDE and RTR and time stamp */ - - pmsg->msg_ctrl = getreg32(addr + MPFS_CAN_RX_MSG_CTRL_CMD_SHIFT); - - /* Ack that it's been removed from the FIFO */ - - putreg32(pmsg->msg_ctrl | MPFS_CAN_RX_MSG_CTRL_CMD_MSGAV_RTRS, - addr + MPFS_CAN_RX_MSG_CTRL_CMD_SHIFT); - - success = CAN_VALID_MSG; - break; - } - } - - return success; -} - -#ifdef CONFIG_DEBUG_CAN_INFO +#ifdef CONFIG_DEBUG_NET_INFO /**************************************************************************** * Name: mpfs_can_get_rx_buffer_status * @@ -2211,7 +1960,7 @@ static uint32_t mpfs_can_get_rx_error_count(mpfs_can_instance_t *priv) return reg; } -#ifdef CONFIG_DEBUG_CAN_INFO +#ifdef CONFIG_DEBUG_NET_INFO /**************************************************************************** * Name: mpfs_can_get_rx_gte96 * @@ -2242,146 +1991,12 @@ static inline bool mpfs_can_get_rx_gte96(mpfs_can_instance_t *priv) } #endif -/**************************************************************************** - * Name: mpfs_can_send_message_ready - * - * Description: - * The mpfs_can_send_message_ready() function will identify the availability - * of buffer to fill with new message in basic CAN operation - * - * Input Parameters: - * priv - Pointer to the private CAN driver state structure - * - * Returned Value: - * This function returns CAN_OK on successful identification of free buffer, - * otherwise it will returns following error codes: - * | Constants | Description | - * |-----------------------|---------------------------------------------| - * | CAN_ERR | Indicates error condition | - * | CAN_INVALID_BUFFER | Indicates invalid buffer number | - * - * Assumptions: - * None - * - ****************************************************************************/ - -static uint8_t mpfs_can_send_message_ready(mpfs_can_instance_t *priv) -{ - uint8_t success = CAN_ERR; - uint8_t buffer_number; - uintptr_t addr; - - if (priv->basic_can_txb_count == 0) - { - return CAN_INVALID_BUFFER; - } - - /* Find next BASIC CAN buffer that is available */ - - for (buffer_number = CAN_TX_BUFFER - priv->basic_can_txb_count; - buffer_number < CAN_TX_BUFFER; buffer_number++) - { - addr = priv->reg_base + MPFS_CAN_TX_MSG_OFFSET - + MPFS_CAN_TX_MSG_TOTAL_SIZE * buffer_number; - - if ((getreg32(addr + MPFS_CAN_TX_MSG_CTRL_CMD_SHIFT) & - MPFS_CAN_TX_MSG_CTRL_CMD_TX_REQ) == 0) - { - /* At least one Tx buffer isn't busy */ - - success = CAN_OK; - break; - } - } - - return success; -} - -/**************************************************************************** - * Name: mpfs_can_send_message - * - * Description: - * The mpfs_can_send_message() function will copy the data to the first - * available buffer set for Basic CAN operation and send data on to the bus. - * Note: Since neither a hardware nor a software FIFO exists, message - * inversion might happen (example, a newer message might be send from the - * transmit buffer prior to an older message) - * - * Input Parameters: - * priv - Pointer to the private CAN driver state structure - * - * Returned Value: - * This function returns CAN_VALID_MSG on successful identification of free - * buffer, otherwise it will returns following error codes: - * | Constants | Description | - * |-----------------------|---------------------------------------------| - * | CAN_NO_MSG | No buffer available for tx | - * | CAN_INVALID_BUFFER | Indicates invalid buffer number | - * - * Assumptions: - * None - * - ****************************************************************************/ - -static uint8_t mpfs_can_send_message(mpfs_can_instance_t *priv) -{ - uint8_t success = CAN_NO_MSG; - uint8_t buffer_number; - mpfs_can_msgobject_t *pmsg = priv->tx_msg; - uintptr_t addr; - - if (priv->basic_can_txb_count == 0) - { - return CAN_INVALID_BUFFER; - } - - /* Find next BASIC CAN buffer that is available */ - - for (buffer_number = CAN_TX_BUFFER - priv->basic_can_txb_count; - buffer_number < CAN_TX_BUFFER; buffer_number++) - { - /* Check which transmit buffer is not busy and use it. */ - - if ((mpfs_can_get_tx_buffer_status(priv) & (1 << buffer_number)) == 0) - { - /* If at least one Tx buffer isn't busy.... */ - - addr = priv->reg_base + MPFS_CAN_TX_MSG_OFFSET - + MPFS_CAN_TX_MSG_TOTAL_SIZE * buffer_number; - - /* CAN ID */ - - putreg32(pmsg->id << MPFS_CAN_MSG_ID_SHIFT, - addr + MPFS_CAN_TX_MSG_ID_SHIFT); - - /* CAN data */ - - putreg32(pmsg->data_low, addr + MPFS_CAN_TX_MSG_DATA_LOW_SHIFT); - putreg32(pmsg->data_high, addr + MPFS_CAN_TX_MSG_DATA_HIGH_SHIFT); - - /* CAN TX msg control command */ - - putreg32(pmsg->msg_ctrl - | MPFS_CAN_TX_MSG_CTRL_CMD_WPN_B - | MPFS_CAN_TX_MSG_CTRL_CMD_WPN_A - | MPFS_CAN_TX_MSG_CTRL_CMD_TX_INT_EBL - | MPFS_CAN_TX_MSG_CTRL_CMD_TX_REQ, - addr + MPFS_CAN_TX_MSG_CTRL_CMD_SHIFT); - - success = CAN_VALID_MSG; - break; - } - } - - return success; -} - /**************************************************************************** * Name: mpfs_can_send_message_abort * * Description: - * The mpfs_can_send_message_abort() function returns the buffer status - * of all transmit(32) buffers + * The mpfs_can_send_message_abort() function requests abortion to busy TX + * buffer * * Input Parameters: * priv - Pointer to the private CAN driver state structure @@ -2488,7 +2103,7 @@ static uint32_t mpfs_can_get_tx_error_count(mpfs_can_instance_t *priv) return reg; } -#ifdef CONFIG_DEBUG_CAN_INFO +#ifdef CONFIG_DEBUG_NET_INFO /**************************************************************************** * Name: mpfs_can_get_tx_gte96 * @@ -2625,17 +2240,15 @@ static void mpfs_can_stop(mpfs_can_instance_t *priv) * ****************************************************************************/ -static int mpfs_ifup(struct net_driver_s *dev) +static int mpfs_ifup(struct netdev_lowerhalf_s *dev) { mpfs_can_instance_t *priv = - (mpfs_can_instance_t *)dev->d_private; + (mpfs_can_instance_t *)dev; mpfs_can_start(priv); priv->bifup = true; - priv->dev.d_buf = (uint8_t *)priv->txdesc; - /* Enable interrupts */ up_enable_irq(priv->irqn); @@ -2660,10 +2273,10 @@ static int mpfs_ifup(struct net_driver_s *dev) * ****************************************************************************/ -static int mpfs_ifdown(struct net_driver_s *dev) +static int mpfs_ifdown(struct netdev_lowerhalf_s *dev) { mpfs_can_instance_t *priv = - (mpfs_can_instance_t *)dev->d_private; + (mpfs_can_instance_t *)dev; mpfs_can_stop(priv); @@ -2691,16 +2304,15 @@ static int mpfs_ifdown(struct net_driver_s *dev) ****************************************************************************/ #ifdef CONFIG_NETDEV_IOCTL -static int mpfs_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg) +static int mpfs_ioctl(struct netdev_lowerhalf_s *dev, int cmd, + unsigned long arg) { -#ifdef CONFIG_DEBUG_CAN_INFO - caninfo("IOCTL received | cmd: %d arg: %ld\n", cmd, arg); -#endif + ninfo("IOCTL received | cmd: %d arg: %ld\n", cmd, arg); #if defined(CONFIG_NETDEV_CAN_BITRATE_IOCTL) || \ defined(CONFIG_NETDEV_CAN_FILTER_IOCTL) mpfs_can_instance_t *priv = - (mpfs_can_instance_t *)dev->d_private; + (mpfs_can_instance_t *)dev; #endif int ret; @@ -2728,21 +2340,13 @@ defined(CONFIG_NETDEV_CAN_FILTER_IOCTL) struct can_ioctl_data_s *req = (struct can_ioctl_data_s *)((uintptr_t)arg); - /* Stop CAN controller */ - - mpfs_can_stop(priv); - if (CAN_OK != mpfs_can_set_bitrate(priv, req->arbi_bitrate)) { - canerr("CAN controller bitrate set failed"); + nerr("CAN controller bitrate set failed"); ret = -EAGAIN; break; } - /* Start CAN controller again */ - - mpfs_can_start(priv); - ret = CAN_OK; } break; @@ -2759,7 +2363,7 @@ defined(CONFIG_NETDEV_CAN_FILTER_IOCTL) if (CAN_OK != mpfs_can_add_filter(priv, req->ftype, req->fid1, req->fid2)) { - canerr("CAN filter add failed"); + nerr("CAN filter add failed"); ret = -EINVAL; break; } @@ -2813,6 +2417,8 @@ defined(CONFIG_NETDEV_CAN_FILTER_IOCTL) int mpfs_can_init(int ncan, uint32_t bitrate) { mpfs_can_instance_t *priv; + struct netdev_lowerhalf_s *dev; + int ret; switch (ncan) { @@ -2824,12 +2430,11 @@ int mpfs_can_init(int ncan, uint32_t bitrate) priv->reg_base = CAN0_BASE; priv->irqn = MPFS_IRQ_CAN0; - /* Initialize TX/RX descriptor structure */ - - priv->txdesc = (struct can_frame *)&g_tx_pool0; - priv->rxdesc = (struct can_frame *)&g_rx_pool0; - - /* Initialize TX/RX message object structure */ + /* Initialize TX/RX message object structure + * NOTE: These are kept for backwards compatibility but are + * no longer used in the main transmit/receive paths which + * now write directly to hardware buffers to avoid race conditions. + */ priv->tx_msg = &g_tx_msg0; priv->rx_msg = &g_rx_msg0; @@ -2844,12 +2449,11 @@ int mpfs_can_init(int ncan, uint32_t bitrate) priv->reg_base = CAN1_BASE; priv->irqn = MPFS_IRQ_CAN1; - /* Initialize TX/RX descriptor structure */ - - priv->txdesc = (struct can_frame *)&g_tx_pool1; - priv->rxdesc = (struct can_frame *)&g_rx_pool1; - - /* Initialize TX/RX message object structure */ + /* Initialize TX/RX message object structure + * NOTE: These are kept for backwards compatibility but are + * no longer used in the main transmit/receive paths which + * now write directly to hardware buffers to avoid race conditions. + */ priv->tx_msg = &g_tx_msg1; priv->rx_msg = &g_rx_msg1; @@ -2857,7 +2461,7 @@ int mpfs_can_init(int ncan, uint32_t bitrate) break; # endif default: - canerr("No such CAN%d available\n", ncan); + nerr("No such CAN%d available\n", ncan); return -ENOTTY; } @@ -2881,7 +2485,7 @@ int mpfs_can_init(int ncan, uint32_t bitrate) if (CAN_OK != mpfs_can_reset_filter(priv)) { - canerr("CAN filter reset and RX buffer initialization failed\n"); + nerr("CAN filter reset and RX buffer initialization failed\n"); return -EAGAIN; } @@ -2899,29 +2503,34 @@ int mpfs_can_init(int ncan, uint32_t bitrate) { /* We could not attach the ISR to the interrupt */ - canerr("Failed to attach to CAN%d IRQ\n", ncan); + nerr("Failed to attach to CAN%d IRQ\n", ncan); return -EAGAIN; } - /* Initialize the driver network device structure */ + /* Initialize the lower-half network device structure */ - priv->dev.d_ifup = mpfs_ifup; /* I/F up (new IP address) callback */ - priv->dev.d_ifdown = mpfs_ifdown; /* I/F down callback */ - priv->dev.d_txavail = mpfs_txavail; /* New TX data callback */ -#ifdef CONFIG_NETDEV_IOCTL - priv->dev.d_ioctl = mpfs_ioctl; /* Support CAN ioctl() calls */ -#endif - priv->dev.d_private = priv; /* Used to recover private state from dev */ + dev = &priv->dev; + dev->ops = &g_netdev_ops; /* Lower-half operations */ - caninfo("CAN driver init done for CAN controller %d\n", ncan); + /* Set quotas for TX/RX buffers */ + + dev->quota[NETPKT_TX] = CAN_TX_BUFFER; + dev->quota[NETPKT_RX] = CAN_RX_BUFFER; + + ninfo("CAN driver init done for CAN controller %d\n", ncan); /* Put the interface in the down state */ - mpfs_ifdown(&priv->dev); + mpfs_ifdown(dev); - /* Register the device with the OS so that socket IOCTLs can be performed */ + /* Register the device with the OS using lower-half interface */ - netdev_register(&priv->dev, NET_LL_CAN); + ret = netdev_lower_register(dev, NET_LL_CAN); + if (ret < 0) + { + nerr("netdev_lower_register failed: %d\n", ret); + return ret; + } return CAN_OK; } diff --git a/boards/risc-v/mpfs/icicle/configs/hwtest/defconfig b/boards/risc-v/mpfs/icicle/configs/hwtest/defconfig index a216bae2b48..920c86baac6 100644 --- a/boards/risc-v/mpfs/icicle/configs/hwtest/defconfig +++ b/boards/risc-v/mpfs/icicle/configs/hwtest/defconfig @@ -79,7 +79,6 @@ CONFIG_NETDEV_PHY_IOCTL=y CONFIG_NETINIT_NOMAC=y CONFIG_NETUTILS_TELNETC=y CONFIG_NETUTILS_TELNETD=y -CONFIG_NET_CAN=y CONFIG_NET_ETH_PKTSIZE=1478 CONFIG_NET_ICMP_SOCKET=y CONFIG_NET_IGMP=y