// SPDX-License-Identifier: GPL-2.0-or-later /******************************************************************************* * * CTU CAN FD IP Core * * Copyright (C) 2015-2018 Ondrej Ille <[email protected]> FEE CTU * Copyright (C) 2018-2021 Ondrej Ille <[email protected]> self-funded * Copyright (C) 2018-2019 Martin Jerabek <[email protected]> FEE CTU * Copyright (C) 2018-2022 Pavel Pisa <[email protected]> FEE CTU/self-funded * * Project advisors: * Jiri Novak <[email protected]> * Pavel Pisa <[email protected]> * * Department of Measurement (http://meas.fel.cvut.cz/) * Faculty of Electrical Engineering (http://www.fel.cvut.cz) * Czech Technical University (http://www.cvut.cz/) ******************************************************************************/ #include <linux/clk.h> #include <linux/errno.h> #include <linux/ethtool.h> #include <linux/init.h> #include <linux/bitfield.h> #include <linux/interrupt.h> #include <linux/io.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/skbuff.h> #include <linux/string.h> #include <linux/types.h> #include <linux/can/error.h> #include <linux/pm_runtime.h> #include "ctucanfd.h" #include "ctucanfd_kregs.h" #include "ctucanfd_kframe.h" #ifdef DEBUG #define ctucan_netdev_dbg(ndev, args...) … #else #define ctucan_netdev_dbg … #endif #define CTUCANFD_ID … /* TX buffer rotation: * - when a buffer transitions to empty state, rotate order and priorities * - if more buffers seem to transition at the same time, rotate by the number of buffers * - it may be assumed that buffers transition to empty state in FIFO order (because we manage * priorities that way) * - at frame filling, do not rotate anything, just increment buffer modulo counter */ #define CTUCANFD_FLAG_RX_FFW_BUFFERED … #define CTUCAN_STATE_TO_TEXT_ENTRY(st) … enum ctucan_txtb_status { … }; enum ctucan_txtb_command { … }; static const struct can_bittiming_const ctu_can_fd_bit_timing_max = …; static const struct can_bittiming_const ctu_can_fd_bit_timing_data_max = …; static const char * const ctucan_state_strings[CAN_STATE_MAX] = …; static void ctucan_write32_le(struct ctucan_priv *priv, enum ctu_can_fd_can_registers reg, u32 val) { … } static void ctucan_write32_be(struct ctucan_priv *priv, enum ctu_can_fd_can_registers reg, u32 val) { … } static u32 ctucan_read32_le(struct ctucan_priv *priv, enum ctu_can_fd_can_registers reg) { … } static u32 ctucan_read32_be(struct ctucan_priv *priv, enum ctu_can_fd_can_registers reg) { … } static void ctucan_write32(struct ctucan_priv *priv, enum ctu_can_fd_can_registers reg, u32 val) { … } static u32 ctucan_read32(struct ctucan_priv *priv, enum ctu_can_fd_can_registers reg) { … } static void ctucan_write_txt_buf(struct ctucan_priv *priv, enum ctu_can_fd_can_registers buf_base, u32 offset, u32 val) { … } #define CTU_CAN_FD_TXTNF(priv) … #define CTU_CAN_FD_ENABLED(priv) … /** * ctucan_state_to_str() - Converts CAN controller state code to corresponding text * @state: CAN controller state code * * Return: Pointer to string representation of the error state */ static const char *ctucan_state_to_str(enum can_state state) { … } /** * ctucan_reset() - Issues software reset request to CTU CAN FD * @ndev: Pointer to net_device structure * * Return: 0 for success, -%ETIMEDOUT if CAN controller does not leave reset */ static int ctucan_reset(struct net_device *ndev) { … } /** * ctucan_set_btr() - Sets CAN bus bit timing in CTU CAN FD * @ndev: Pointer to net_device structure * @bt: Pointer to Bit timing structure * @nominal: True - Nominal bit timing, False - Data bit timing * * Return: 0 - OK, -%EPERM if controller is enabled */ static int ctucan_set_btr(struct net_device *ndev, struct can_bittiming *bt, bool nominal) { … } /** * ctucan_set_bittiming() - CAN set nominal bit timing routine * @ndev: Pointer to net_device structure * * Return: 0 on success, -%EPERM on error */ static int ctucan_set_bittiming(struct net_device *ndev) { … } /** * ctucan_set_data_bittiming() - CAN set data bit timing routine * @ndev: Pointer to net_device structure * * Return: 0 on success, -%EPERM on error */ static int ctucan_set_data_bittiming(struct net_device *ndev) { … } /** * ctucan_set_secondary_sample_point() - Sets secondary sample point in CTU CAN FD * @ndev: Pointer to net_device structure * * Return: 0 on success, -%EPERM if controller is enabled */ static int ctucan_set_secondary_sample_point(struct net_device *ndev) { … } /** * ctucan_set_mode() - Sets CTU CAN FDs mode * @priv: Pointer to private data * @mode: Pointer to controller modes to be set */ static void ctucan_set_mode(struct ctucan_priv *priv, const struct can_ctrlmode *mode) { … } /** * ctucan_chip_start() - This routine starts the driver * @ndev: Pointer to net_device structure * * Routine expects that chip is in reset state. It setups initial * Tx buffers for FIFO priorities, sets bittiming, enables interrupts, * switches core to operational mode and changes controller * state to %CAN_STATE_STOPPED. * * Return: 0 on success and failure value on error */ static int ctucan_chip_start(struct net_device *ndev) { … } /** * ctucan_do_set_mode() - Sets mode of the driver * @ndev: Pointer to net_device structure * @mode: Tells the mode of the driver * * This check the drivers state and calls the corresponding modes to set. * * Return: 0 on success and failure value on error */ static int ctucan_do_set_mode(struct net_device *ndev, enum can_mode mode) { … } /** * ctucan_get_tx_status() - Gets status of TXT buffer * @priv: Pointer to private data * @buf: Buffer index (0-based) * * Return: Status of TXT buffer */ static enum ctucan_txtb_status ctucan_get_tx_status(struct ctucan_priv *priv, u8 buf) { … } /** * ctucan_is_txt_buf_writable() - Checks if frame can be inserted to TXT Buffer * @priv: Pointer to private data * @buf: Buffer index (0-based) * * Return: True - Frame can be inserted to TXT Buffer, False - If attempted, frame will not be * inserted to TXT Buffer */ static bool ctucan_is_txt_buf_writable(struct ctucan_priv *priv, u8 buf) { … } /** * ctucan_insert_frame() - Inserts frame to TXT buffer * @priv: Pointer to private data * @cf: Pointer to CAN frame to be inserted * @buf: TXT Buffer index to which frame is inserted (0-based) * @isfdf: True - CAN FD Frame, False - CAN 2.0 Frame * * Return: True - Frame inserted successfully * False - Frame was not inserted due to one of: * 1. TXT Buffer is not writable (it is in wrong state) * 2. Invalid TXT buffer index * 3. Invalid frame length */ static bool ctucan_insert_frame(struct ctucan_priv *priv, const struct canfd_frame *cf, u8 buf, bool isfdf) { … } /** * ctucan_give_txtb_cmd() - Applies command on TXT buffer * @priv: Pointer to private data * @cmd: Command to give * @buf: Buffer index (0-based) */ static void ctucan_give_txtb_cmd(struct ctucan_priv *priv, enum ctucan_txtb_command cmd, u8 buf) { … } /** * ctucan_start_xmit() - Starts the transmission * @skb: sk_buff pointer that contains data to be Txed * @ndev: Pointer to net_device structure * * Invoked from upper layers to initiate transmission. Uses the next available free TXT Buffer and * populates its fields to start the transmission. * * Return: %NETDEV_TX_OK on success, %NETDEV_TX_BUSY when no free TXT buffer is available, * negative return values reserved for error cases */ static netdev_tx_t ctucan_start_xmit(struct sk_buff *skb, struct net_device *ndev) { … } /** * ctucan_read_rx_frame() - Reads frame from RX FIFO * @priv: Pointer to CTU CAN FD's private data * @cf: Pointer to CAN frame struct * @ffw: Previously read frame format word * * Note: Frame format word must be read separately and provided in 'ffw'. */ static void ctucan_read_rx_frame(struct ctucan_priv *priv, struct canfd_frame *cf, u32 ffw) { … } /** * ctucan_rx() - Called from CAN ISR to complete the received frame processing * @ndev: Pointer to net_device structure * * This function is invoked from the CAN isr(poll) to process the Rx frames. It does minimal * processing and invokes "netif_receive_skb" to complete further processing. * Return: 1 when frame is passed to the network layer, 0 when the first frame word is read but * system is out of free SKBs temporally and left code to resolve SKB allocation later, * -%EAGAIN in a case of empty Rx FIFO. */ static int ctucan_rx(struct net_device *ndev) { … } /** * ctucan_read_fault_state() - Reads CTU CAN FDs fault confinement state. * @priv: Pointer to private data * * Returns: Fault confinement state of controller */ static enum can_state ctucan_read_fault_state(struct ctucan_priv *priv) { … } /** * ctucan_get_rec_tec() - Reads REC/TEC counter values from controller * @priv: Pointer to private data * @bec: Pointer to Error counter structure */ static void ctucan_get_rec_tec(struct ctucan_priv *priv, struct can_berr_counter *bec) { … } /** * ctucan_err_interrupt() - Error frame ISR * @ndev: net_device pointer * @isr: interrupt status register value * * This is the CAN error interrupt and it will check the type of error and forward the error * frame to upper layers. */ static void ctucan_err_interrupt(struct net_device *ndev, u32 isr) { … } /** * ctucan_rx_poll() - Poll routine for rx packets (NAPI) * @napi: NAPI structure pointer * @quota: Max number of rx packets to be processed. * * This is the poll routine for rx part. It will process the packets maximux quota value. * * Return: Number of packets received */ static int ctucan_rx_poll(struct napi_struct *napi, int quota) { … } /** * ctucan_rotate_txb_prio() - Rotates priorities of TXT Buffers * @ndev: net_device pointer */ static void ctucan_rotate_txb_prio(struct net_device *ndev) { … } /** * ctucan_tx_interrupt() - Tx done Isr * @ndev: net_device pointer */ static void ctucan_tx_interrupt(struct net_device *ndev) { … } /** * ctucan_interrupt() - CAN Isr * @irq: irq number * @dev_id: device id pointer * * This is the CTU CAN FD ISR. It checks for the type of interrupt * and invokes the corresponding ISR. * * Return: * IRQ_NONE - If CAN device is in sleep mode, IRQ_HANDLED otherwise */ static irqreturn_t ctucan_interrupt(int irq, void *dev_id) { … } /** * ctucan_chip_stop() - Driver stop routine * @ndev: Pointer to net_device structure * * This is the drivers stop routine. It will disable the * interrupts and disable the controller. */ static void ctucan_chip_stop(struct net_device *ndev) { … } /** * ctucan_open() - Driver open routine * @ndev: Pointer to net_device structure * * This is the driver open routine. * Return: 0 on success and failure value on error */ static int ctucan_open(struct net_device *ndev) { … } /** * ctucan_close() - Driver close routine * @ndev: Pointer to net_device structure * * Return: 0 always */ static int ctucan_close(struct net_device *ndev) { … } /** * ctucan_get_berr_counter() - error counter routine * @ndev: Pointer to net_device structure * @bec: Pointer to can_berr_counter structure * * This is the driver error counter routine. * Return: 0 on success and failure value on error */ static int ctucan_get_berr_counter(const struct net_device *ndev, struct can_berr_counter *bec) { … } static const struct net_device_ops ctucan_netdev_ops = …; static const struct ethtool_ops ctucan_ethtool_ops = …; int ctucan_suspend(struct device *dev) { … } EXPORT_SYMBOL(…); int ctucan_resume(struct device *dev) { … } EXPORT_SYMBOL(…); int ctucan_probe_common(struct device *dev, void __iomem *addr, int irq, unsigned int ntxbufs, unsigned long can_clk_rate, int pm_enable_call, void (*set_drvdata_fnc)(struct device *dev, struct net_device *ndev)) { … } EXPORT_SYMBOL(…); MODULE_LICENSE(…) …; MODULE_AUTHOR(…) …; MODULE_AUTHOR(…) …; MODULE_AUTHOR(…) …; MODULE_DESCRIPTION(…) …;