diff options
Diffstat (limited to 'drivers/net/can')
44 files changed, 2484 insertions, 363 deletions
diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig index fff259247d52..b2dcc1e5a388 100644 --- a/drivers/net/can/Kconfig +++ b/drivers/net/can/Kconfig @@ -71,23 +71,6 @@ config CAN_CALC_BITTIMING arguments "tq", "prop_seg", "phase_seg1", "phase_seg2" and "sjw". If unsure, say Y. -config CAN_LEDS - bool "Enable LED triggers for Netlink based drivers" - depends on LEDS_CLASS - # The netdev trigger (LEDS_TRIGGER_NETDEV) should be able to do - # everything that this driver is doing. This is marked as broken - # because it uses stuff that is intended to be changed or removed. - # Please consider switching to the netdev trigger and confirm it - # fulfills your needs instead of fixing this driver. - depends on BROKEN - select LEDS_TRIGGERS - help - This option adds two LED triggers for packet receive and transmit - events on each supported CAN device. - - Say Y here if you are working on a system with led-class supported - LEDs and you want to use them as canbus activity indicators. - config CAN_AT91 tristate "Atmel AT91 onchip CAN controller" depends on (ARCH_AT91 || COMPILE_TEST) && HAS_IOMEM @@ -170,6 +153,7 @@ config PCH_CAN source "drivers/net/can/c_can/Kconfig" source "drivers/net/can/cc770/Kconfig" +source "drivers/net/can/ctucanfd/Kconfig" source "drivers/net/can/ifi_canfd/Kconfig" source "drivers/net/can/m_can/Kconfig" source "drivers/net/can/mscan/Kconfig" diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile index 1e660afcb61b..0af85983634c 100644 --- a/drivers/net/can/Makefile +++ b/drivers/net/can/Makefile @@ -16,6 +16,7 @@ obj-y += softing/ obj-$(CONFIG_CAN_AT91) += at91_can.o obj-$(CONFIG_CAN_CC770) += cc770/ obj-$(CONFIG_CAN_C_CAN) += c_can/ +obj-$(CONFIG_CAN_CTUCANFD) += ctucanfd/ obj-$(CONFIG_CAN_FLEXCAN) += flexcan/ obj-$(CONFIG_CAN_GRCAN) += grcan.o obj-$(CONFIG_CAN_IFI_CANFD) += ifi_canfd/ diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c index a00655ccda02..29ed0d3cd171 100644 --- a/drivers/net/can/at91_can.c +++ b/drivers/net/can/at91_can.c @@ -23,7 +23,6 @@ #include <linux/can/dev.h> #include <linux/can/error.h> -#include <linux/can/led.h> #define AT91_MB_MASK(i) ((1 << (i)) - 1) @@ -618,8 +617,6 @@ static void at91_read_msg(struct net_device *dev, unsigned int mb) stats->rx_bytes += cf->len; netif_receive_skb(skb); - - can_led_event(dev, CAN_LED_EVENT_RX); } /** @@ -854,7 +851,6 @@ static void at91_irq_tx(struct net_device *dev, u32 reg_sr) mb - get_mb_tx_first(priv), NULL); dev->stats.tx_packets++; - can_led_event(dev, CAN_LED_EVENT_TX); } } @@ -1101,8 +1097,6 @@ static int at91_open(struct net_device *dev) goto out_close; } - can_led_event(dev, CAN_LED_EVENT_OPEN); - /* start chip and queuing */ at91_chip_start(dev); napi_enable(&priv->napi); @@ -1133,8 +1127,6 @@ static int at91_close(struct net_device *dev) close_candev(dev); - can_led_event(dev, CAN_LED_EVENT_STOP); - return 0; } @@ -1317,7 +1309,7 @@ static int at91_can_probe(struct platform_device *pdev) priv->pdata = dev_get_platdata(&pdev->dev); priv->mb0_id = 0x7ff; - netif_napi_add(dev, &priv->napi, at91_poll, get_mb_rx_num(priv)); + netif_napi_add_weight(dev, &priv->napi, at91_poll, get_mb_rx_num(priv)); if (at91_is_sam9263(priv)) dev->sysfs_groups[0] = &at91_sysfs_attr_group; @@ -1331,8 +1323,6 @@ static int at91_can_probe(struct platform_device *pdev) goto exit_free; } - devm_can_led_init(dev); - dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%d)\n", priv->reg_base, dev->irq); diff --git a/drivers/net/can/c_can/c_can_main.c b/drivers/net/can/c_can/c_can_main.c index faa217f26771..a7362af0babb 100644 --- a/drivers/net/can/c_can/c_can_main.c +++ b/drivers/net/can/c_can/c_can_main.c @@ -40,7 +40,6 @@ #include <linux/can.h> #include <linux/can/dev.h> #include <linux/can/error.h> -#include <linux/can/led.h> #include "c_can.h" @@ -759,7 +758,6 @@ static void c_can_do_tx(struct net_device *dev) stats->tx_bytes += bytes; stats->tx_packets += pkts; - can_led_event(dev, CAN_LED_EVENT_TX); tail = c_can_get_tx_tail(tx_ring); @@ -906,9 +904,6 @@ static int c_can_do_rx_poll(struct net_device *dev, int quota) quota -= n; } - if (pkts) - can_led_event(dev, CAN_LED_EVENT_RX); - return pkts; } @@ -1182,8 +1177,6 @@ static int c_can_open(struct net_device *dev) if (err) goto exit_start_fail; - can_led_event(dev, CAN_LED_EVENT_OPEN); - napi_enable(&priv->napi); /* enable status change, error and module interrupts */ c_can_irq_control(priv, true); @@ -1214,8 +1207,6 @@ static int c_can_close(struct net_device *dev) c_can_reset_ram(priv, false); c_can_pm_runtime_put_sync(priv); - can_led_event(dev, CAN_LED_EVENT_STOP); - return 0; } @@ -1246,7 +1237,8 @@ struct net_device *alloc_c_can_dev(int msg_obj_num) priv->tx.tail = 0; priv->tx.obj_num = msg_obj_tx_num; - netif_napi_add(dev, &priv->napi, c_can_poll, priv->msg_obj_rx_num); + netif_napi_add_weight(dev, &priv->napi, c_can_poll, + priv->msg_obj_rx_num); priv->dev = dev; priv->can.bittiming_const = &c_can_bittiming_const; @@ -1364,8 +1356,6 @@ static const struct net_device_ops c_can_netdev_ops = { int register_c_can_dev(struct net_device *dev) { - int err; - /* Deactivate pins to prevent DRA7 DCAN IP from being * stuck in transition when module is disabled. * Pins are activated in c_can_start() and deactivated @@ -1377,10 +1367,7 @@ int register_c_can_dev(struct net_device *dev) dev->netdev_ops = &c_can_netdev_ops; c_can_set_ethtool_ops(dev); - err = register_candev(dev); - if (!err) - devm_can_led_init(dev); - return err; + return register_candev(dev); } EXPORT_SYMBOL_GPL(register_c_can_dev); diff --git a/drivers/net/can/ctucanfd/Kconfig b/drivers/net/can/ctucanfd/Kconfig new file mode 100644 index 000000000000..6e2073351a8f --- /dev/null +++ b/drivers/net/can/ctucanfd/Kconfig @@ -0,0 +1,34 @@ +config CAN_CTUCANFD + tristate "CTU CAN-FD IP core" if COMPILE_TEST + help + This driver adds support for the CTU CAN FD open-source IP core. + More documentation and core sources at project page + (https://gitlab.fel.cvut.cz/canbus/ctucanfd_ip_core). + The core integration to Xilinx Zynq system as platform driver + is available (https://gitlab.fel.cvut.cz/canbus/zynq/zynq-can-sja1000-top). + Implementation on Intel FPGA-based PCI Express board is available + from project (https://gitlab.fel.cvut.cz/canbus/pcie-ctucanfd) and + on Intel SoC from project (https://gitlab.fel.cvut.cz/canbus/intel-soc-ctucanfd). + Guidepost CTU FEE CAN bus projects page https://canbus.pages.fel.cvut.cz/ . + +config CAN_CTUCANFD_PCI + tristate "CTU CAN-FD IP core PCI/PCIe driver" + depends on PCI + select CAN_CTUCANFD + help + This driver adds PCI/PCIe support for CTU CAN-FD IP core. + The project providing FPGA design for Intel EP4CGX15 based DB4CGX15 + PCIe board with PiKRON.com designed transceiver riser shield is available + at https://gitlab.fel.cvut.cz/canbus/pcie-ctucanfd . + +config CAN_CTUCANFD_PLATFORM + tristate "CTU CAN-FD IP core platform (FPGA, SoC) driver" + depends on HAS_IOMEM && (OF || COMPILE_TEST) + select CAN_CTUCANFD + help + The core has been tested together with OpenCores SJA1000 + modified to be CAN FD frames tolerant on MicroZed Zynq based + MZ_APO education kits designed by Petr Porazil from PiKRON.com + company. FPGA design https://gitlab.fel.cvut.cz/canbus/zynq/zynq-can-sja1000-top. + The kit description at the Computer Architectures course pages + https://cw.fel.cvut.cz/wiki/courses/b35apo/documentation/mz_apo/start . diff --git a/drivers/net/can/ctucanfd/Makefile b/drivers/net/can/ctucanfd/Makefile new file mode 100644 index 000000000000..8078f1f2c30f --- /dev/null +++ b/drivers/net/can/ctucanfd/Makefile @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Makefile for the CTU CAN-FD IP module drivers +# + +obj-$(CONFIG_CAN_CTUCANFD) := ctucanfd.o +ctucanfd-y := ctucanfd_base.o + +obj-$(CONFIG_CAN_CTUCANFD_PCI) += ctucanfd_pci.o +obj-$(CONFIG_CAN_CTUCANFD_PLATFORM) += ctucanfd_platform.o diff --git a/drivers/net/can/ctucanfd/ctucanfd.h b/drivers/net/can/ctucanfd/ctucanfd.h new file mode 100644 index 000000000000..0e9904f6a05d --- /dev/null +++ b/drivers/net/can/ctucanfd/ctucanfd.h @@ -0,0 +1,82 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/******************************************************************************* + * + * CTU CAN FD IP Core + * + * Copyright (C) 2015-2018 Ondrej Ille <ondrej.ille@gmail.com> FEE CTU + * Copyright (C) 2018-2021 Ondrej Ille <ondrej.ille@gmail.com> self-funded + * Copyright (C) 2018-2019 Martin Jerabek <martin.jerabek01@gmail.com> FEE CTU + * Copyright (C) 2018-2021 Pavel Pisa <pisa@cmp.felk.cvut.cz> FEE CTU/self-funded + * + * Project advisors: + * Jiri Novak <jnovak@fel.cvut.cz> + * Pavel Pisa <pisa@cmp.felk.cvut.cz> + * + * Department of Measurement (http://meas.fel.cvut.cz/) + * Faculty of Electrical Engineering (http://www.fel.cvut.cz) + * Czech Technical University (http://www.cvut.cz/) + ******************************************************************************/ + +#ifndef __CTUCANFD__ +#define __CTUCANFD__ + +#include <linux/netdevice.h> +#include <linux/can/dev.h> +#include <linux/list.h> + +enum ctu_can_fd_can_registers; + +struct ctucan_priv { + struct can_priv can; /* must be first member! */ + + void __iomem *mem_base; + u32 (*read_reg)(struct ctucan_priv *priv, + enum ctu_can_fd_can_registers reg); + void (*write_reg)(struct ctucan_priv *priv, + enum ctu_can_fd_can_registers reg, u32 val); + + unsigned int txb_head; + unsigned int txb_tail; + u32 txb_prio; + unsigned int ntxbufs; + spinlock_t tx_lock; /* spinlock to serialize allocation and processing of TX buffers */ + + struct napi_struct napi; + struct device *dev; + struct clk *can_clk; + + int irq_flags; + unsigned long drv_flags; + + u32 rxfrm_first_word; + + struct list_head peers_on_pdev; +}; + +/** + * ctucan_probe_common - Device type independent registration call + * + * This function does all the memory allocation and registration for the CAN + * device. + * + * @dev: Handle to the generic device structure + * @addr: Base address of CTU CAN FD core address + * @irq: Interrupt number + * @ntxbufs: Number of implemented Tx buffers + * @can_clk_rate: Clock rate, if 0 then clock are taken from device node + * @pm_enable_call: Whether pm_runtime_enable should be called + * @set_drvdata_fnc: Function to set network driver data for physical device + * + * Return: 0 on success and failure value on error + */ +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)); + +int ctucan_suspend(struct device *dev) __maybe_unused; +int ctucan_resume(struct device *dev) __maybe_unused; + +#endif /*__CTUCANFD__*/ diff --git a/drivers/net/can/ctucanfd/ctucanfd_base.c b/drivers/net/can/ctucanfd/ctucanfd_base.c new file mode 100644 index 000000000000..64990bf20fdc --- /dev/null +++ b/drivers/net/can/ctucanfd/ctucanfd_base.c @@ -0,0 +1,1452 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/******************************************************************************* + * + * CTU CAN FD IP Core + * + * Copyright (C) 2015-2018 Ondrej Ille <ondrej.ille@gmail.com> FEE CTU + * Copyright (C) 2018-2021 Ondrej Ille <ondrej.ille@gmail.com> self-funded + * Copyright (C) 2018-2019 Martin Jerabek <martin.jerabek01@gmail.com> FEE CTU + * Copyright (C) 2018-2022 Pavel Pisa <pisa@cmp.felk.cvut.cz> FEE CTU/self-funded + * + * Project advisors: + * Jiri Novak <jnovak@fel.cvut.cz> + * Pavel Pisa <pisa@cmp.felk.cvut.cz> + * + * 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/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...) \ + netdev_dbg(ndev, args) +#else +#define ctucan_netdev_dbg(...) do { } while (0) +#endif + +#define CTUCANFD_ID 0xCAFD + +/* 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 1 + +#define CTUCAN_STATE_TO_TEXT_ENTRY(st) \ + [st] = #st + +enum ctucan_txtb_status { + TXT_NOT_EXIST = 0x0, + TXT_RDY = 0x1, + TXT_TRAN = 0x2, + TXT_ABTP = 0x3, + TXT_TOK = 0x4, + TXT_ERR = 0x6, + TXT_ABT = 0x7, + TXT_ETY = 0x8, +}; + +enum ctucan_txtb_command { + TXT_CMD_SET_EMPTY = 0x01, + TXT_CMD_SET_READY = 0x02, + TXT_CMD_SET_ABORT = 0x04 +}; + +static const struct can_bittiming_const ctu_can_fd_bit_timing_max = { + .name = "ctu_can_fd", + .tseg1_min = 2, + .tseg1_max = 190, + .tseg2_min = 1, + .tseg2_max = 63, + .sjw_max = 31, + .brp_min = 1, + .brp_max = 8, + .brp_inc = 1, +}; + +static const struct can_bittiming_const ctu_can_fd_bit_timing_data_max = { + .name = "ctu_can_fd", + .tseg1_min = 2, + .tseg1_max = 94, + .tseg2_min = 1, + .tseg2_max = 31, + .sjw_max = 31, + .brp_min = 1, + .brp_max = 2, + .brp_inc = 1, +}; + +static const char * const ctucan_state_strings[CAN_STATE_MAX] = { + CTUCAN_STATE_TO_TEXT_ENTRY(CAN_STATE_ERROR_ACTIVE), + CTUCAN_STATE_TO_TEXT_ENTRY(CAN_STATE_ERROR_WARNING), + CTUCAN_STATE_TO_TEXT_ENTRY(CAN_STATE_ERROR_PASSIVE), + CTUCAN_STATE_TO_TEXT_ENTRY(CAN_STATE_BUS_OFF), + CTUCAN_STATE_TO_TEXT_ENTRY(CAN_STATE_STOPPED), + CTUCAN_STATE_TO_TEXT_ENTRY(CAN_STATE_SLEEPING) +}; + +static void ctucan_write32_le(struct ctucan_priv *priv, + enum ctu_can_fd_can_registers reg, u32 val) +{ + iowrite32(val, priv->mem_base + reg); +} + +static void ctucan_write32_be(struct ctucan_priv *priv, + enum ctu_can_fd_can_registers reg, u32 val) +{ + iowrite32be(val, priv->mem_base + reg); +} + +static u32 ctucan_read32_le(struct ctucan_priv *priv, + enum ctu_can_fd_can_registers reg) +{ + return ioread32(priv->mem_base + reg); +} + +static u32 ctucan_read32_be(struct ctucan_priv *priv, + enum ctu_can_fd_can_registers reg) +{ + return ioread32be(priv->mem_base + reg); +} + +static void ctucan_write32(struct ctucan_priv *priv, enum ctu_can_fd_can_registers reg, u32 val) +{ + priv->write_reg(priv, reg, val); +} + +static u32 ctucan_read32(struct ctucan_priv *priv, enum ctu_can_fd_can_registers reg) +{ + return priv->read_reg(priv, reg); +} + +static void ctucan_write_txt_buf(struct ctucan_priv *priv, enum ctu_can_fd_can_registers buf_base, + u32 offset, u32 val) +{ + priv->write_reg(priv, buf_base + offset, val); +} + +#define CTU_CAN_FD_TXTNF(priv) (!!FIELD_GET(REG_STATUS_TXNF, ctucan_read32(priv, CTUCANFD_STATUS))) +#define CTU_CAN_FD_ENABLED(priv) (!!FIELD_GET(REG_MODE_ENA, ctucan_read32(priv, CTUCANFD_MODE))) + +/** + * 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) +{ + const char *txt = NULL; + + if (state >= 0 && state < CAN_STATE_MAX) + txt = ctucan_state_strings[state]; + return txt ? txt : "UNKNOWN"; +} + +/** + * 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) +{ + struct ctucan_priv *priv = netdev_priv(ndev); + int i = 100; + + ctucan_write32(priv, CTUCANFD_MODE, REG_MODE_RST); + clear_bit(CTUCANFD_FLAG_RX_FFW_BUFFERED, &priv->drv_flags); + + do { + u16 device_id = FIELD_GET(REG_DEVICE_ID_DEVICE_ID, + ctucan_read32(priv, CTUCANFD_DEVICE_ID)); + + if (device_id == 0xCAFD) + return 0; + if (!i--) { + netdev_warn(ndev, "device did not leave reset\n"); + return -ETIMEDOUT; + } + usleep_range(100, 200); + } while (1); +} + +/** + * 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) +{ + struct ctucan_priv *priv = netdev_priv(ndev); + int max_ph1_len = 31; + u32 btr = 0; + u32 prop_seg = bt->prop_seg; + u32 phase_seg1 = bt->phase_seg1; + + if (CTU_CAN_FD_ENABLED(priv)) { + netdev_err(ndev, "BUG! Cannot set bittiming - CAN is enabled\n"); + return -EPERM; + } + + if (nominal) + max_ph1_len = 63; + + /* The timing calculation functions have only constraints on tseg1, which is prop_seg + + * phase1_seg combined. tseg1 is then split in half and stored into prog_seg and phase_seg1. + * In CTU CAN FD, PROP is 6/7 bits wide but PH1 only 6/5, so we must re-distribute the + * values here. + */ + if (phase_seg1 > max_ph1_len) { + prop_seg += phase_seg1 - max_ph1_len; + phase_seg1 = max_ph1_len; + bt->prop_seg = prop_seg; + bt->phase_seg1 = phase_seg1; + } + + if (nominal) { + btr = FIELD_PREP(REG_BTR_PROP, prop_seg); + btr |= FIELD_PREP(REG_BTR_PH1, phase_seg1); + btr |= FIELD_PREP(REG_BTR_PH2, bt->phase_seg2); + btr |= FIELD_PREP(REG_BTR_BRP, bt->brp); + btr |= FIELD_PREP(REG_BTR_SJW, bt->sjw); + + ctucan_write32(priv, CTUCANFD_BTR, btr); + } else { + btr = FIELD_PREP(REG_BTR_FD_PROP_FD, prop_seg); + btr |= FIELD_PREP(REG_BTR_FD_PH1_FD, phase_seg1); + btr |= FIELD_PREP(REG_BTR_FD_PH2_FD, bt->phase_seg2); + btr |= FIELD_PREP(REG_BTR_FD_BRP_FD, bt->brp); + btr |= FIELD_PREP(REG_BTR_FD_SJW_FD, bt->sjw); + + ctucan_write32(priv, CTUCANFD_BTR_FD, btr); + } + + return 0; +} + +/** + * 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) +{ + struct ctucan_priv *priv = netdev_priv(ndev); + struct can_bittiming *bt = &priv->can.bittiming; + + /* Note that bt may be modified here */ + return ctucan_set_btr(ndev, bt, true); +} + +/** + * 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) +{ + struct ctucan_priv *priv = netdev_priv(ndev); + struct can_bittiming *dbt = &priv->can.data_bittiming; + + /* Note that dbt may be modified here */ + return ctucan_set_btr(ndev, dbt, false); +} + +/** + * 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) +{ + struct ctucan_priv *priv = netdev_priv(ndev); + struct can_bittiming *dbt = &priv->can.data_bittiming; + int ssp_offset = 0; + u32 ssp_cfg = 0; /* No SSP by default */ + + if (CTU_CAN_FD_ENABLED(priv)) { + netdev_err(ndev, "BUG! Cannot set SSP - CAN is enabled\n"); + return -EPERM; + } + + /* Use SSP for bit-rates above 1 Mbits/s */ + if (dbt->bitrate > 1000000) { + /* Calculate SSP in minimal time quanta */ + ssp_offset = (priv->can.clock.freq / 1000) * dbt->sample_point / dbt->bitrate; + + if (ssp_offset > 127) { + netdev_warn(ndev, "SSP offset saturated to 127\n"); + ssp_offset = 127; + } + + ssp_cfg = FIELD_PREP(REG_TRV_DELAY_SSP_OFFSET, ssp_offset); + ssp_cfg |= FIELD_PREP(REG_TRV_DELAY_SSP_SRC, 0x1); + } + + ctucan_write32(priv, CTUCANFD_TRV_DELAY, ssp_cfg); + + return 0; +} + +/** + * 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) +{ + u32 mode_reg = ctucan_read32(priv, CTUCANFD_MODE); + + mode_reg = (mode->flags & CAN_CTRLMODE_LOOPBACK) ? + (mode_reg | REG_MODE_ILBP) : + (mode_reg & ~REG_MODE_ILBP); + + mode_reg = (mode->flags & CAN_CTRLMODE_LISTENONLY) ? + (mode_reg | REG_MODE_BMM) : + (mode_reg & ~REG_MODE_BMM); + + mode_reg = (mode->flags & CAN_CTRLMODE_FD) ? + (mode_reg | REG_MODE_FDE) : + (mode_reg & ~REG_MODE_FDE); + + mode_reg = (mode->flags & CAN_CTRLMODE_PRESUME_ACK) ? + (mode_reg | REG_MODE_ACF) : + (mode_reg & ~REG_MODE_ACF); + + mode_reg = (mode->flags & CAN_CTRLMODE_FD_NON_ISO) ? + (mode_reg | REG_MODE_NISOFD) : + (mode_reg & ~REG_MODE_NISOFD); + + /* One shot mode supported indirectly via Retransmit limit */ + mode_reg &= ~FIELD_PREP(REG_MODE_RTRTH, 0xF); + mode_reg = (mode->flags & CAN_CTRLMODE_ONE_SHOT) ? + (mode_reg | REG_MODE_RTRLE) : + (mode_reg & ~REG_MODE_RTRLE); + + /* Some bits fixed: + * TSTM - Off, User shall not be able to change REC/TEC by hand during operation + */ + mode_reg &= ~REG_MODE_TSTM; + + ctucan_write32(priv, CTUCANFD_MODE, mode_reg); +} + +/** + * 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) +{ + struct ctucan_priv *priv = netdev_priv(ndev); + u32 int_ena, int_msk; + u32 mode_reg; + int err; + struct can_ctrlmode mode; + + priv->txb_prio = 0x01234567; + priv->txb_head = 0; + priv->txb_tail = 0; + ctucan_write32(priv, CTUCANFD_TX_PRIORITY, priv->txb_prio); + + /* Configure bit-rates and ssp */ + err = ctucan_set_bittiming(ndev); + if (err < 0) + return err; + + err = ctucan_set_data_bittiming(ndev); + if (err < 0) + return err; + + err = ctucan_set_secondary_sample_point(ndev); + if (err < 0) + return err; + + /* Configure modes */ + mode.flags = priv->can.ctrlmode; + mode.mask = 0xFFFFFFFF; + ctucan_set_mode(priv, &mode); + + /* Configure interrupts */ + int_ena = REG_INT_STAT_RBNEI | + REG_INT_STAT_TXBHCI | + REG_INT_STAT_EWLI | + REG_INT_STAT_FCSI; + + /* Bus error reporting -> Allow Error/Arb.lost interrupts */ + if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) { + int_ena |= REG_INT_STAT_ALI | + REG_INT_STAT_BEI; + } + + int_msk = ~int_ena; /* Mask all disabled interrupts */ + + /* It's after reset, so there is no need to clear anything */ + ctucan_write32(priv, CTUCANFD_INT_MASK_SET, int_msk); + ctucan_write32(priv, CTUCANFD_INT_ENA_SET, int_ena); + + /* Controller enters ERROR_ACTIVE on initial FCSI */ + priv->can.state = CAN_STATE_STOPPED; + + /* Enable the controller */ + mode_reg = ctucan_read32(priv, CTUCANFD_MODE); + mode_reg |= REG_MODE_ENA; + ctucan_write32(priv, CTUCANFD_MODE, mode_reg); + + return 0; +} + +/** + * 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) +{ + int ret; + + switch (mode) { + case CAN_MODE_START: + ret = ctucan_reset(ndev); + if (ret < 0) + return ret; + ret = ctucan_chip_start(ndev); + if (ret < 0) { + netdev_err(ndev, "ctucan_chip_start failed!\n"); + return ret; + } + netif_wake_queue(ndev); + break; + default: + ret = -EOPNOTSUPP; + break; + } + + return ret; +} + +/** + * 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) +{ + u32 tx_status = ctucan_read32(priv, CTUCANFD_TX_STATUS); + enum ctucan_txtb_status status = (tx_status >> (buf * 4)) & 0x7; + + return status; +} + +/** + * 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) +{ + enum ctucan_txtb_status buf_status; + + buf_status = ctucan_get_tx_status(priv, buf); + if (buf_status == TXT_RDY || buf_status == TXT_TRAN || buf_status == TXT_ABTP) + return false; + + return true; +} + +/** + * 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) +{ + u32 buf_base; + u32 ffw = 0; + u32 idw = 0; + unsigned int i; + + if (buf >= priv->ntxbufs) + return false; + + if (!ctucan_is_txt_buf_writable(priv, buf)) + return false; + + if (cf->len > CANFD_MAX_DLEN) + return false; + + /* Prepare Frame format */ + if (cf->can_id & CAN_RTR_FLAG) + ffw |= REG_FRAME_FORMAT_W_RTR; + + if (cf->can_id & CAN_EFF_FLAG) + ffw |= REG_FRAME_FORMAT_W_IDE; + + if (isfdf) { + ffw |= REG_FRAME_FORMAT_W_FDF; + if (cf->flags & CANFD_BRS) + ffw |= REG_FRAME_FORMAT_W_BRS; + } + + ffw |= FIELD_PREP(REG_FRAME_FORMAT_W_DLC, can_fd_len2dlc(cf->len)); + + /* Prepare identifier */ + if (cf->can_id & CAN_EFF_FLAG) + idw = cf->can_id & CAN_EFF_MASK; + else + idw = FIELD_PREP(REG_IDENTIFIER_W_IDENTIFIER_BASE, cf->can_id & CAN_SFF_MASK); + + /* Write ID, Frame format, Don't write timestamp -> Time triggered transmission disabled */ + buf_base = (buf + 1) * 0x100; + ctucan_write_txt_buf(priv, buf_base, CTUCANFD_FRAME_FORMAT_W, ffw); + ctucan_write_txt_buf(priv, buf_base, CTUCANFD_IDENTIFIER_W, idw); + + /* Write Data payload */ + if (!(cf->can_id & CAN_RTR_FLAG)) { + for (i = 0; i < cf->len; i += 4) { + u32 data = le32_to_cpu(*(__le32 *)(cf->data + i)); + + ctucan_write_txt_buf(priv, buf_base, CTUCANFD_DATA_1_4_W + i, data); + } + } + + return true; +} + +/** + * 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) +{ + u32 tx_cmd = cmd; + + tx_cmd |= 1 << (buf + 8); + ctucan_write32(priv, CTUCANFD_TX_COMMAND, tx_cmd); +} + +/** + * 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) +{ + struct ctucan_priv *priv = netdev_priv(ndev); + struct canfd_frame *cf = (struct canfd_frame *)skb->data; + u32 txtb_id; + bool ok; + unsigned long flags; + + if (can_dropped_invalid_skb(ndev, skb)) + return NETDEV_TX_OK; + + if (unlikely(!CTU_CAN_FD_TXTNF(priv))) { + netif_stop_queue(ndev); + netdev_err(ndev, "BUG!, no TXB free when queue awake!\n"); + return NETDEV_TX_BUSY; + } + + txtb_id = priv->txb_head % priv->ntxbufs; + ctucan_netdev_dbg(ndev, "%s: using TXB#%u\n", __func__, txtb_id); + ok = ctucan_insert_frame(priv, cf, txtb_id, can_is_canfd_skb(skb)); + + if (!ok) { + netdev_err(ndev, "BUG! TXNF set but cannot insert frame into TXTB! HW Bug?"); + kfree_skb(skb); + ndev->stats.tx_dropped++; + return NETDEV_TX_OK; + } + + can_put_echo_skb(skb, ndev, txtb_id, 0); + + spin_lock_irqsave(&priv->tx_lock, flags); + ctucan_give_txtb_cmd(priv, TXT_CMD_SET_READY, txtb_id); + priv->txb_head++; + + /* Check if all TX buffers are full */ + if (!CTU_CAN_FD_TXTNF(priv)) + netif_stop_queue(ndev); + + spin_unlock_irqrestore(&priv->tx_lock, flags); + + return NETDEV_TX_OK; +} + +/** + * 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) +{ + u32 idw; + unsigned int i; + unsigned int wc; + unsigned int len; + + idw = ctucan_read32(priv, CTUCANFD_RX_DATA); + if (FIELD_GET(REG_FRAME_FORMAT_W_IDE, ffw)) + cf->can_id = (idw & CAN_EFF_MASK) | CAN_EFF_FLAG; + else + cf->can_id = (idw >> 18) & CAN_SFF_MASK; + + /* BRS, ESI, RTR Flags */ + cf->flags = 0; + if (FIELD_GET(REG_FRAME_FORMAT_W_FDF, ffw)) { + if (FIELD_GET(REG_FRAME_FORMAT_W_BRS, ffw)) + cf->flags |= CANFD_BRS; + if (FIELD_GET(REG_FRAME_FORMAT_W_ESI_RSV, ffw)) + cf->flags |= CANFD_ESI; + } else if (FIELD_GET(REG_FRAME_FORMAT_W_RTR, ffw)) { + cf->can_id |= CAN_RTR_FLAG; + } + + wc = FIELD_GET(REG_FRAME_FORMAT_W_RWCNT, ffw) - 3; + + /* DLC */ + if (FIELD_GET(REG_FRAME_FORMAT_W_DLC, ffw) <= 8) { + len = FIELD_GET(REG_FRAME_FORMAT_W_DLC, ffw); + } else { + if (FIELD_GET(REG_FRAME_FORMAT_W_FDF, ffw)) + len = wc << 2; + else + len = 8; + } + cf->len = len; + if (unlikely(len > wc * 4)) + len = wc * 4; + + /* Timestamp - Read and throw away */ + ctucan_read32(priv, CTUCANFD_RX_DATA); + ctucan_read32(priv, CTUCANFD_RX_DATA); + + /* Data */ + for (i = 0; i < len; i += 4) { + u32 data = ctucan_read32(priv, CTUCANFD_RX_DATA); + *(__le32 *)(cf->data + i) = cpu_to_le32(data); + } + while (unlikely(i < wc * 4)) { + ctucan_read32(priv, CTUCANFD_RX_DATA); + i += 4; + } +} + +/** + * 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) +{ + struct ctucan_priv *priv = netdev_priv(ndev); + struct net_device_stats *stats = &ndev->stats; + struct canfd_frame *cf; + struct sk_buff *skb; + u32 ffw; + + if (test_bit(CTUCANFD_FLAG_RX_FFW_BUFFERED, &priv->drv_flags)) { + ffw = priv->rxfrm_first_word; + clear_bit(CTUCANFD_FLAG_RX_FFW_BUFFERED, &priv->drv_flags); + } else { + ffw = ctucan_read32(priv, CTUCANFD_RX_DATA); + } + + if (!FIELD_GET(REG_FRAME_FORMAT_W_RWCNT, ffw)) + return -EAGAIN; + + if (FIELD_GET(REG_FRAME_FORMAT_W_FDF, ffw)) + skb = alloc_canfd_skb(ndev, &cf); + else + skb = alloc_can_skb(ndev, (struct can_frame **)&cf); + + if (unlikely(!skb)) { + priv->rxfrm_first_word = ffw; + set_bit(CTUCANFD_FLAG_RX_FFW_BUFFERED, &priv->drv_flags); + return 0; + } + + ctucan_read_rx_frame(priv, cf, ffw); + + stats->rx_bytes += cf->len; + stats->rx_packets++; + netif_receive_skb(skb); + + return 1; +} + +/** + * 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) +{ + u32 fs; + u32 rec_tec; + u32 ewl; + + fs = ctucan_read32(priv, CTUCANFD_EWL); + rec_tec = ctucan_read32(priv, CTUCANFD_REC); + ewl = FIELD_GET(REG_EWL_EW_LIMIT, fs); + + if (FIELD_GET(REG_EWL_ERA, fs)) { + if (ewl > FIELD_GET(REG_REC_REC_VAL, rec_tec) && + ewl > FIELD_GET(REG_REC_TEC_VAL, rec_tec)) + return CAN_STATE_ERROR_ACTIVE; + else + return CAN_STATE_ERROR_WARNING; + } else if (FIELD_GET(REG_EWL_ERP, fs)) { + return CAN_STATE_ERROR_PASSIVE; + } else if (FIELD_GET(REG_EWL_BOF, fs)) { + return CAN_STATE_BUS_OFF; + } + + WARN(true, "Invalid error state"); + return CAN_STATE_ERROR_PASSIVE; +} + +/** + * 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) +{ + u32 err_ctrs = ctucan_read32(priv, CTUCANFD_REC); + + bec->rxerr = FIELD_GET(REG_REC_REC_VAL, err_ctrs); + bec->txerr = FIELD_GET(REG_REC_TEC_VAL, err_ctrs); +} + +/** + * 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) +{ + struct ctucan_priv *priv = netdev_priv(ndev); + struct net_device_stats *stats = &ndev->stats; + struct can_frame *cf; + struct sk_buff *skb; + enum can_state state; + struct can_berr_counter bec; + u32 err_capt_alc; + int dologerr = net_ratelimit(); + + ctucan_get_rec_tec(priv, &bec); + state = ctucan_read_fault_state(priv); + err_capt_alc = ctucan_read32(priv, CTUCANFD_ERR_CAPT); + + if (dologerr) + netdev_info(ndev, "%s: ISR = 0x%08x, rxerr %d, txerr %d, error type %lu, pos %lu, ALC id_field %lu, bit %lu\n", + __func__, isr, bec.rxerr, bec.txerr, + FIELD_GET(REG_ERR_CAPT_ERR_TYPE, err_capt_alc), + FIELD_GET(REG_ERR_CAPT_ERR_POS, err_capt_alc), + FIELD_GET(REG_ERR_CAPT_ALC_ID_FIELD, err_capt_alc), + FIELD_GET(REG_ERR_CAPT_ALC_BIT, err_capt_alc)); + + skb = alloc_can_err_skb(ndev, &cf); + + /* EWLI: error warning limit condition met + * FCSI: fault confinement state changed + * ALI: arbitration lost (just informative) + * BEI: bus error interrupt + */ + if (FIELD_GET(REG_INT_STAT_FCSI, isr) || FIELD_GET(REG_INT_STAT_EWLI, isr)) { + netdev_info(ndev, "state changes from %s to %s\n", + ctucan_state_to_str(priv->can.state), + ctucan_state_to_str(state)); + + if (priv->can.state == state) + netdev_warn(ndev, + "current and previous state is the same! (missed interrupt?)\n"); + + priv->can.state = state; + switch (state) { + case CAN_STATE_BUS_OFF: + priv->can.can_stats.bus_off++; + can_bus_off(ndev); + if (skb) + cf->can_id |= CAN_ERR_BUSOFF; + break; + case CAN_STATE_ERROR_PASSIVE: + priv->can.can_stats.error_passive++; + if (skb) { + cf->can_id |= CAN_ERR_CRTL; + cf->data[1] = (bec.rxerr > 127) ? + CAN_ERR_CRTL_RX_PASSIVE : + CAN_ERR_CRTL_TX_PASSIVE; + cf->data[6] = bec.txerr; + cf->data[7] = bec.rxerr; + } + break; + case CAN_STATE_ERROR_WARNING: + priv->can.can_stats.error_warning++; + if (skb) { + cf->can_id |= CAN_ERR_CRTL; + cf->data[1] |= (bec.txerr > bec.rxerr) ? + CAN_ERR_CRTL_TX_WARNING : + CAN_ERR_CRTL_RX_WARNING; + cf->data[6] = bec.txerr; + cf->data[7] = bec.rxerr; + } + break; + case CAN_STATE_ERROR_ACTIVE: + cf->data[1] = CAN_ERR_CRTL_ACTIVE; + cf->data[6] = bec.txerr; + cf->data[7] = bec.rxerr; + break; + default: + netdev_warn(ndev, "unhandled error state (%d:%s)!\n", + state, ctucan_state_to_str(state)); + break; + } + } + + /* Check for Arbitration Lost interrupt */ + if (FIELD_GET(REG_INT_STAT_ALI, isr)) { + if (dologerr) + netdev_info(ndev, "arbitration lost\n"); + priv->can.can_stats.arbitration_lost++; + if (skb) { + cf->can_id |= CAN_ERR_LOSTARB; + cf->data[0] = CAN_ERR_LOSTARB_UNSPEC; + } + } + + /* Check for Bus Error interrupt */ + if (FIELD_GET(REG_INT_STAT_BEI, isr)) { + netdev_info(ndev, "bus error\n"); + priv->can.can_stats.bus_error++; + stats->rx_errors++; + if (skb) { + cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; + cf->data[2] = CAN_ERR_PROT_UNSPEC; + cf->data[3] = CAN_ERR_PROT_LOC_UNSPEC; + } + } + + if (skb) { + stats->rx_packets++; + stats->rx_bytes += cf->can_dlc; + netif_rx(skb); + } +} + +/** + * 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) +{ + struct net_device *ndev = napi->dev; + struct ctucan_priv *priv = netdev_priv(ndev); + int work_done = 0; + u32 status; + u32 framecnt; + int res = 1; + + framecnt = FIELD_GET(REG_RX_STATUS_RXFRC, ctucan_read32(priv, CTUCANFD_RX_STATUS)); + while (framecnt && work_done < quota && res > 0) { + res = ctucan_rx(ndev); + work_done++; + framecnt = FIELD_GET(REG_RX_STATUS_RXFRC, ctucan_read32(priv, CTUCANFD_RX_STATUS)); + } + + /* Check for RX FIFO Overflow */ + status = ctucan_read32(priv, CTUCANFD_STATUS); + if (FIELD_GET(REG_STATUS_DOR, status)) { + struct net_device_stats *stats = &ndev->stats; + struct can_frame *cf; + struct sk_buff *skb; + + netdev_info(ndev, "rx_poll: rx fifo overflow\n"); + stats->rx_over_errors++; + stats->rx_errors++; + skb = alloc_can_err_skb(ndev, &cf); + if (skb) { + cf->can_id |= CAN_ERR_CRTL; + cf->data[1] |= CAN_ERR_CRTL_RX_OVERFLOW; + stats->rx_packets++; + stats->rx_bytes += cf->can_dlc; + netif_rx(skb); + } + + /* Clear Data Overrun */ + ctucan_write32(priv, CTUCANFD_COMMAND, REG_COMMAND_CDO); + } + + if (!framecnt && res != 0) { + if (napi_complete_done(napi, work_done)) { + /* Clear and enable RBNEI. It is level-triggered, so + * there is no race condition. + */ + ctucan_write32(priv, CTUCANFD_INT_STAT, REG_INT_STAT_RBNEI); + ctucan_write32(priv, CTUCANFD_INT_MASK_CLR, REG_INT_STAT_RBNEI); + } + } + + return work_done; +} + +/** + * ctucan_rotate_txb_prio() - Rotates priorities of TXT Buffers + * @ndev: net_device pointer + */ +static void ctucan_rotate_txb_prio(struct net_device *ndev) +{ + struct ctucan_priv *priv = netdev_priv(ndev); + u32 prio = priv->txb_prio; + + prio = (prio << 4) | ((prio >> ((priv->ntxbufs - 1) * 4)) & 0xF); + ctucan_netdev_dbg(ndev, "%s: from 0x%08x to 0x%08x\n", __func__, priv->txb_prio, prio); + priv->txb_prio = prio; + ctucan_write32(priv, CTUCANFD_TX_PRIORITY, prio); +} + +/** + * ctucan_tx_interrupt() - Tx done Isr + * @ndev: net_device pointer + */ +static void ctucan_tx_interrupt(struct net_device *ndev) +{ + struct ctucan_priv *priv = netdev_priv(ndev); + struct net_device_stats *stats = &ndev->stats; + bool first = true; + bool some_buffers_processed; + unsigned long flags; + enum ctucan_txtb_status txtb_status; + u32 txtb_id; + + /* read tx_status + * if txb[n].finished (bit 2) + * if ok -> echo + * if error / aborted -> ?? (find how to handle oneshot mode) + * txb_tail++ + */ + do { + spin_lock_irqsave(&priv->tx_lock, flags); + + some_buffers_processed = false; + while ((int)(priv->txb_head - priv->txb_tail) > 0) { + txtb_id = priv->txb_tail % priv->ntxbufs; + txtb_status = ctucan_get_tx_status(priv, txtb_id); + + ctucan_netdev_dbg(ndev, "TXI: TXB#%u: status 0x%x\n", txtb_id, txtb_status); + + switch (txtb_status) { + case TXT_TOK: + ctucan_netdev_dbg(ndev, "TXT_OK\n"); + stats->tx_bytes += can_get_echo_skb(ndev, txtb_id, NULL); + stats->tx_packets++; + break; + case TXT_ERR: + /* This indicated that retransmit limit has been reached. Obviously + * we should not echo the frame, but also not indicate any kind of + * error. If desired, it was already reported (possible multiple + * times) on each arbitration lost. + */ + netdev_warn(ndev, "TXB in Error state\n"); + can_free_echo_skb(ndev, txtb_id, NULL); + stats->tx_dropped++; + break; + case TXT_ABT: + /* Same as for TXT_ERR, only with different cause. We *could* + * re-queue the frame, but multiqueue/abort is not supported yet + * anyway. + */ + netdev_warn(ndev, "TXB in Aborted state\n"); + can_free_echo_skb(ndev, txtb_id, NULL); + stats->tx_dropped++; + break; + default: + /* Bug only if the first buffer is not finished, otherwise it is + * pretty much expected. + */ + if (first) { + netdev_err(ndev, + "BUG: TXB#%u not in a finished state (0x%x)!\n", + txtb_id, txtb_status); + spin_unlock_irqrestore(&priv->tx_lock, flags); + /* do not clear nor wake */ + return; + } + goto clear; + } + priv->txb_tail++; + first = false; + some_buffers_processed = true; + /* Adjust priorities *before* marking the buffer as empty. */ + ctucan_rotate_txb_prio(ndev); + ctucan_give_txtb_cmd(priv, TXT_CMD_SET_EMPTY, txtb_id); + } +clear: + spin_unlock_irqrestore(&priv->tx_lock, flags); + + /* If no buffers were processed this time, we cannot clear - that would introduce + * a race condition. + */ + if (some_buffers_processed) { + /* Clear the interrupt again. We do not want to receive again interrupt for + * the buffer already handled. If it is the last finished one then it would + * cause log of spurious interrupt. + */ + ctucan_write32(priv, CTUCANFD_INT_STAT, REG_INT_STAT_TXBHCI); + } + } while (some_buffers_processed); + + spin_lock_irqsave(&priv->tx_lock, flags); + + /* Check if at least one TX buffer is free */ + if (CTU_CAN_FD_TXTNF(priv)) + netif_wake_queue(ndev); + + spin_unlock_irqrestore(&priv->tx_lock, flags); +} + +/** + * ctucan_interrupt() - CAN Isr + * @irq: irq number + * @dev_id: device id poniter + * + * 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) +{ + struct net_device *ndev = (struct net_device *)dev_id; + struct ctucan_priv *priv = netdev_priv(ndev); + u32 isr, icr; + u32 imask; + int irq_loops; + + for (irq_loops = 0; irq_loops < 10000; irq_loops++) { + /* Get the interrupt status */ + isr = ctucan_read32(priv, CTUCANFD_INT_STAT); + + if (!isr) + return irq_loops ? IRQ_HANDLED : IRQ_NONE; + + /* Receive Buffer Not Empty Interrupt */ + if (FIELD_GET(REG_INT_STAT_RBNEI, isr)) { + ctucan_netdev_dbg(ndev, "RXBNEI\n"); + /* Mask RXBNEI the first, then clear interrupt and schedule NAPI. Even if + * another IRQ fires, RBNEI will always be 0 (masked). + */ + icr = REG_INT_STAT_RBNEI; + ctucan_write32(priv, CTUCANFD_INT_MASK_SET, icr); + ctucan_write32(priv, CTUCANFD_INT_STAT, icr); + napi_schedule(&priv->napi); + } + + /* TXT Buffer HW Command Interrupt */ + if (FIELD_GET(REG_INT_STAT_TXBHCI, isr)) { + ctucan_netdev_dbg(ndev, "TXBHCI\n"); + /* Cleared inside */ + ctucan_tx_interrupt(ndev); + } + + /* Error interrupts */ + if (FIELD_GET(REG_INT_STAT_EWLI, isr) || + FIELD_GET(REG_INT_STAT_FCSI, isr) || + FIELD_GET(REG_INT_STAT_ALI, isr)) { + icr = isr & (REG_INT_STAT_EWLI | REG_INT_STAT_FCSI | REG_INT_STAT_ALI); + + ctucan_netdev_dbg(ndev, "some ERR interrupt: clearing 0x%08x\n", icr); + ctucan_write32(priv, CTUCANFD_INT_STAT, icr); + ctucan_err_interrupt(ndev, isr); + } + /* Ignore RI, TI, LFI, RFI, BSI */ + } + + netdev_err(ndev, "%s: stuck interrupt (isr=0x%08x), stopping\n", __func__, isr); + + if (FIELD_GET(REG_INT_STAT_TXBHCI, isr)) { + int i; + + netdev_err(ndev, "txb_head=0x%08x txb_tail=0x%08x\n", + priv->txb_head, priv->txb_tail); + for (i = 0; i < priv->ntxbufs; i++) { + u32 status = ctucan_get_tx_status(priv, i); + + netdev_err(ndev, "txb[%d] txb status=0x%08x\n", i, status); + } + } + + imask = 0xffffffff; + ctucan_write32(priv, CTUCANFD_INT_ENA_CLR, imask); + ctucan_write32(priv, CTUCANFD_INT_MASK_SET, imask); + + return IRQ_HANDLED; +} + +/** + * 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) +{ + struct ctucan_priv *priv = netdev_priv(ndev); + u32 mask = 0xffffffff; + u32 mode; + + /* Disable interrupts and disable CAN */ + ctucan_write32(priv, CTUCANFD_INT_ENA_CLR, mask); + ctucan_write32(priv, CTUCANFD_INT_MASK_SET, mask); + mode = ctucan_read32(priv, CTUCANFD_MODE); + mode &= ~REG_MODE_ENA; + ctucan_write32(priv, CTUCANFD_MODE, mode); + + priv->can.state = CAN_STATE_STOPPED; +} + +/** + * 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) +{ + struct ctucan_priv *priv = netdev_priv(ndev); + int ret; + + ret = pm_runtime_get_sync(priv->dev); + if (ret < 0) { + netdev_err(ndev, "%s: pm_runtime_get failed(%d)\n", + __func__, ret); + pm_runtime_put_noidle(priv->dev); + return ret; + } + + ret = ctucan_reset(ndev); + if (ret < 0) + goto err_reset; + + /* Common open */ + ret = open_candev(ndev); + if (ret) { + netdev_warn(ndev, "open_candev failed!\n"); + goto err_open; + } + + ret = request_irq(ndev->irq, ctucan_interrupt, priv->irq_flags, ndev->name, ndev); + if (ret < 0) { + netdev_err(ndev, "irq allocation for CAN failed\n"); + goto err_irq; + } + + ret = ctucan_chip_start(ndev); + if (ret < 0) { + netdev_err(ndev, "ctucan_chip_start failed!\n"); + goto err_chip_start; + } + + netdev_info(ndev, "ctu_can_fd device registered\n"); + napi_enable(&priv->napi); + netif_start_queue(ndev); + + return 0; + +err_chip_start: + free_irq(ndev->irq, ndev); +err_irq: + close_candev(ndev); +err_open: +err_reset: + pm_runtime_put(priv->dev); + + return ret; +} + +/** + * ctucan_close() - Driver close routine + * @ndev: Pointer to net_device structure + * + * Return: 0 always + */ +static int ctucan_close(struct net_device *ndev) +{ + struct ctucan_priv *priv = netdev_priv(ndev); + + netif_stop_queue(ndev); + napi_disable(&priv->napi); + ctucan_chip_stop(ndev); + free_irq(ndev->irq, ndev); + close_candev(ndev); + + pm_runtime_put(priv->dev); + + return 0; +} + +/** + * 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) +{ + struct ctucan_priv *priv = netdev_priv(ndev); + int ret; + + ret = pm_runtime_get_sync(priv->dev); + if (ret < 0) { + netdev_err(ndev, "%s: pm_runtime_get failed(%d)\n", __func__, ret); + pm_runtime_put_noidle(priv->dev); + return ret; + } + + ctucan_get_rec_tec(priv, bec); + pm_runtime_put(priv->dev); + + return 0; +} + +static const struct net_device_ops ctucan_netdev_ops = { + .ndo_open = ctucan_open, + .ndo_stop = ctucan_close, + .ndo_start_xmit = ctucan_start_xmit, + .ndo_change_mtu = can_change_mtu, +}; + +int ctucan_suspend(struct device *dev) +{ + struct net_device *ndev = dev_get_drvdata(dev); + struct ctucan_priv *priv = netdev_priv(ndev); + + if (netif_running(ndev)) { + netif_stop_queue(ndev); + netif_device_detach(ndev); + } + + priv->can.state = CAN_STATE_SLEEPING; + + return 0; +} +EXPORT_SYMBOL(ctucan_suspend); + +int ctucan_resume(struct device *dev) +{ + struct net_device *ndev = dev_get_drvdata(dev); + struct ctucan_priv *priv = netdev_priv(ndev); + + priv->can.state = CAN_STATE_ERROR_ACTIVE; + + if (netif_running(ndev)) { + netif_device_attach(ndev); + netif_start_queue(ndev); + } + + return 0; +} +EXPORT_SYMBOL(ctucan_resume); + +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)) +{ + struct ctucan_priv *priv; + struct net_device *ndev; + int ret; + + /* Create a CAN device instance */ + ndev = alloc_candev(sizeof(struct ctucan_priv), ntxbufs); + if (!ndev) + return -ENOMEM; + + priv = netdev_priv(ndev); + spin_lock_init(&priv->tx_lock); + INIT_LIST_HEAD(&priv->peers_on_pdev); + priv->ntxbufs = ntxbufs; + priv->dev = dev; + priv->can.bittiming_const = &ctu_can_fd_bit_timing_max; + priv->can.data_bittiming_const = &ctu_can_fd_bit_timing_data_max; + priv->can.do_set_mode = ctucan_do_set_mode; + + /* Needed for timing adjustment to be performed as soon as possible */ + priv->can.do_set_bittiming = ctucan_set_bittiming; + priv->can.do_set_data_bittiming = ctucan_set_data_bittiming; + + priv->can.do_get_berr_counter = ctucan_get_berr_counter; + priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK + | CAN_CTRLMODE_LISTENONLY + | CAN_CTRLMODE_FD + | CAN_CTRLMODE_PRESUME_ACK + | CAN_CTRLMODE_BERR_REPORTING + | CAN_CTRLMODE_FD_NON_ISO + | CAN_CTRLMODE_ONE_SHOT; + priv->mem_base = addr; + + /* Get IRQ for the device */ + ndev->irq = irq; + ndev->flags |= IFF_ECHO; /* We support local echo */ + + if (set_drvdata_fnc) + set_drvdata_fnc(dev, ndev); + SET_NETDEV_DEV(ndev, dev); + ndev->netdev_ops = &ctucan_netdev_ops; + + /* Getting the can_clk info */ + if (!can_clk_rate) { + priv->can_clk = devm_clk_get(dev, NULL); + if (IS_ERR(priv->can_clk)) { + dev_err(dev, "Device clock not found.\n"); + ret = PTR_ERR(priv->can_clk); + goto err_free; + } + can_clk_rate = clk_get_rate(priv->can_clk); + } + + priv->write_reg = ctucan_write32_le; + priv->read_reg = ctucan_read32_le; + + if (pm_enable_call) + pm_runtime_enable(dev); + ret = pm_runtime_get_sync(dev); + if (ret < 0) { + netdev_err(ndev, "%s: pm_runtime_get failed(%d)\n", + __func__, ret); + pm_runtime_put_noidle(priv->dev); + goto err_pmdisable; + } + + /* Check for big-endianity and set according IO-accessors */ + if ((ctucan_read32(priv, CTUCANFD_DEVICE_ID) & 0xFFFF) != CTUCANFD_ID) { + priv->write_reg = ctucan_write32_be; + priv->read_reg = ctucan_read32_be; + if ((ctucan_read32(priv, CTUCANFD_DEVICE_ID) & 0xFFFF) != CTUCANFD_ID) { + netdev_err(ndev, "CTU_CAN_FD signature not found\n"); + ret = -ENODEV; + goto err_deviceoff; + } + } + + ret = ctucan_reset(ndev); + if (ret < 0) + goto err_deviceoff; + + priv->can.clock.freq = can_clk_rate; + + netif_napi_add(ndev, &priv->napi, ctucan_rx_poll, NAPI_POLL_WEIGHT); + + ret = register_candev(ndev); + if (ret) { + dev_err(dev, "fail to register failed (err=%d)\n", ret); + goto err_deviceoff; + } + + pm_runtime_put(dev); + + netdev_dbg(ndev, "mem_base=0x%p irq=%d clock=%d, no. of txt buffers:%d\n", + priv->mem_base, ndev->irq, priv->can.clock.freq, priv->ntxbufs); + + return 0; + +err_deviceoff: + pm_runtime_put(priv->dev); +err_pmdisable: + if (pm_enable_call) + pm_runtime_disable(dev); +err_free: + list_del_init(&priv->peers_on_pdev); + free_candev(ndev); + return ret; +} +EXPORT_SYMBOL(ctucan_probe_common); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Martin Jerabek <martin.jerabek01@gmail.com>"); +MODULE_AUTHOR("Pavel Pisa <pisa@cmp.felk.cvut.cz>"); +MODULE_AUTHOR("Ondrej Ille <ondrej.ille@gmail.com>"); +MODULE_DESCRIPTION("CTU CAN FD interface"); diff --git a/drivers/net/can/ctucanfd/ctucanfd_kframe.h b/drivers/net/can/ctucanfd/ctucanfd_kframe.h new file mode 100644 index 000000000000..3491299eaac2 --- /dev/null +++ b/drivers/net/can/ctucanfd/ctucanfd_kframe.h @@ -0,0 +1,77 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/******************************************************************************* + * + * CTU CAN FD IP Core + * + * Copyright (C) 2015-2018 Ondrej Ille <ondrej.ille@gmail.com> FEE CTU + * Copyright (C) 2018-2021 Ondrej Ille <ondrej.ille@gmail.com> self-funded + * Copyright (C) 2018-2019 Martin Jerabek <martin.jerabek01@gmail.com> FEE CTU + * Copyright (C) 2018-2021 Pavel Pisa <pisa@cmp.felk.cvut.cz> FEE CTU/self-funded + * + * Project advisors: + * Jiri Novak <jnovak@fel.cvut.cz> + * Pavel Pisa <pisa@cmp.felk.cvut.cz> + * + * Department of Measurement (http://meas.fel.cvut.cz/) + * Faculty of Electrical Engineering (http://www.fel.cvut.cz) + * Czech Technical University (http://www.cvut.cz/) + ******************************************************************************/ + +/* This file is autogenerated, DO NOT EDIT! */ + +#ifndef __CTU_CAN_FD_CAN_FD_FRAME_FORMAT__ +#define __CTU_CAN_FD_CAN_FD_FRAME_FORMAT__ + +#include <linux/bits.h> + +/* CAN_Frame_format memory map */ +enum ctu_can_fd_can_frame_format { + CTUCANFD_FRAME_FORMAT_W = 0x0, + CTUCANFD_IDENTIFIER_W = 0x4, + CTUCANFD_TIMESTAMP_L_W = 0x8, + CTUCANFD_TIMESTAMP_U_W = 0xc, + CTUCANFD_DATA_1_4_W = 0x10, + CTUCANFD_DATA_5_8_W = 0x14, + CTUCANFD_DATA_61_64_W = 0x4c, +}; + +/* CAN_FD_Frame_format memory region */ + +/* FRAME_FORMAT_W registers */ +#define REG_FRAME_FORMAT_W_DLC GENMASK(3, 0) +#define REG_FRAME_FORMAT_W_RTR BIT(5) +#define REG_FRAME_FORMAT_W_IDE BIT(6) +#define REG_FRAME_FORMAT_W_FDF BIT(7) +#define REG_FRAME_FORMAT_W_BRS BIT(9) +#define REG_FRAME_FORMAT_W_ESI_RSV BIT(10) +#define REG_FRAME_FORMAT_W_RWCNT GENMASK(15, 11) + +/* IDENTIFIER_W registers */ +#define REG_IDENTIFIER_W_IDENTIFIER_EXT GENMASK(17, 0) +#define REG_IDENTIFIER_W_IDENTIFIER_BASE GENMASK(28, 18) + +/* TIMESTAMP_L_W registers */ +#define REG_TIMESTAMP_L_W_TIME_STAMP_L_W GENMASK(31, 0) + +/* TIMESTAMP_U_W registers */ +#define REG_TIMESTAMP_U_W_TIMESTAMP_U_W GENMASK(31, 0) + +/* DATA_1_4_W registers */ +#define REG_DATA_1_4_W_DATA_1 GENMASK(7, 0) +#define REG_DATA_1_4_W_DATA_2 GENMASK(15, 8) +#define REG_DATA_1_4_W_DATA_3 GENMASK(23, 16) +#define REG_DATA_1_4_W_DATA_4 GENMASK(31, 24) + +/* DATA_5_8_W registers */ +#define REG_DATA_5_8_W_DATA_5 GENMASK(7, 0) +#define REG_DATA_5_8_W_DATA_6 GENMASK(15, 8) +#define REG_DATA_5_8_W_DATA_7 GENMASK(23, 16) +#define REG_DATA_5_8_W_DATA_8 GENMASK(31, 24) + +/* DATA_61_64_W registers */ +#define REG_DATA_61_64_W_DATA_61 GENMASK(7, 0) +#define REG_DATA_61_64_W_DATA_62 GENMASK(15, 8) +#define REG_DATA_61_64_W_DATA_63 GENMASK(23, 16) +#define REG_DATA_61_64_W_DATA_64 GENMASK(31, 24) + +#endif diff --git a/drivers/net/can/ctucanfd/ctucanfd_kregs.h b/drivers/net/can/ctucanfd/ctucanfd_kregs.h new file mode 100644 index 000000000000..edc1c1a24348 --- /dev/null +++ b/drivers/net/can/ctucanfd/ctucanfd_kregs.h @@ -0,0 +1,325 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/******************************************************************************* + * + * CTU CAN FD IP Core + * + * Copyright (C) 2015-2018 Ondrej Ille <ondrej.ille@gmail.com> FEE CTU + * Copyright (C) 2018-2021 Ondrej Ille <ondrej.ille@gmail.com> self-funded + * Copyright (C) 2018-2019 Martin Jerabek <martin.jerabek01@gmail.com> FEE CTU + * Copyright (C) 2018-2021 Pavel Pisa <pisa@cmp.felk.cvut.cz> FEE CTU/self-funded + * + * Project advisors: + * Jiri Novak <jnovak@fel.cvut.cz> + * Pavel Pisa <pisa@cmp.felk.cvut.cz> + * + * Department of Measurement (http://meas.fel.cvut.cz/) + * Faculty of Electrical Engineering (http://www.fel.cvut.cz) + * Czech Technical University (http://www.cvut.cz/) + ******************************************************************************/ + +/* This file is autogenerated, DO NOT EDIT! */ + +#ifndef __CTU_CAN_FD_CAN_FD_REGISTER_MAP__ +#define __CTU_CAN_FD_CAN_FD_REGISTER_MAP__ + +#include <linux/bits.h> + +/* CAN_Registers memory map */ +enum ctu_can_fd_can_registers { + CTUCANFD_DEVICE_ID = 0x0, + CTUCANFD_VERSION = 0x2, + CTUCANFD_MODE = 0x4, + CTUCANFD_SETTINGS = 0x6, + CTUCANFD_STATUS = 0x8, + CTUCANFD_COMMAND = 0xc, + CTUCANFD_INT_STAT = 0x10, + CTUCANFD_INT_ENA_SET = 0x14, + CTUCANFD_INT_ENA_CLR = 0x18, + CTUCANFD_INT_MASK_SET = 0x1c, + CTUCANFD_INT_MASK_CLR = 0x20, + CTUCANFD_BTR = 0x24, + CTUCANFD_BTR_FD = 0x28, + CTUCANFD_EWL = 0x2c, + CTUCANFD_ERP = 0x2d, + CTUCANFD_FAULT_STATE = 0x2e, + CTUCANFD_REC = 0x30, + CTUCANFD_TEC = 0x32, + CTUCANFD_ERR_NORM = 0x34, + CTUCANFD_ERR_FD = 0x36, + CTUCANFD_CTR_PRES = 0x38, + CTUCANFD_FILTER_A_MASK = 0x3c, + CTUCANFD_FILTER_A_VAL = 0x40, + CTUCANFD_FILTER_B_MASK = 0x44, + CTUCANFD_FILTER_B_VAL = 0x48, + CTUCANFD_FILTER_C_MASK = 0x4c, + CTUCANFD_FILTER_C_VAL = 0x50, + CTUCANFD_FILTER_RAN_LOW = 0x54, + CTUCANFD_FILTER_RAN_HIGH = 0x58, + CTUCANFD_FILTER_CONTROL = 0x5c, + CTUCANFD_FILTER_STATUS = 0x5e, + CTUCANFD_RX_MEM_INFO = 0x60, + CTUCANFD_RX_POINTERS = 0x64, + CTUCANFD_RX_STATUS = 0x68, + CTUCANFD_RX_SETTINGS = 0x6a, + CTUCANFD_RX_DATA = 0x6c, + CTUCANFD_TX_STATUS = 0x70, + CTUCANFD_TX_COMMAND = 0x74, + CTUCANFD_TX_PRIORITY = 0x78, + CTUCANFD_ERR_CAPT = 0x7c, + CTUCANFD_ALC = 0x7e, + CTUCANFD_TRV_DELAY = 0x80, + CTUCANFD_SSP_CFG = 0x82, + CTUCANFD_RX_FR_CTR = 0x84, + CTUCANFD_TX_FR_CTR = 0x88, + CTUCANFD_DEBUG_REGISTER = 0x8c, + CTUCANFD_YOLO_REG = 0x90, + CTUCANFD_TIMESTAMP_LOW = 0x94, + CTUCANFD_TIMESTAMP_HIGH = 0x98, + CTUCANFD_TXTB1_DATA_1 = 0x100, + CTUCANFD_TXTB1_DATA_2 = 0x104, + CTUCANFD_TXTB1_DATA_20 = 0x14c, + CTUCANFD_TXTB2_DATA_1 = 0x200, + CTUCANFD_TXTB2_DATA_2 = 0x204, + CTUCANFD_TXTB2_DATA_20 = 0x24c, + CTUCANFD_TXTB3_DATA_1 = 0x300, + CTUCANFD_TXTB3_DATA_2 = 0x304, + CTUCANFD_TXTB3_DATA_20 = 0x34c, + CTUCANFD_TXTB4_DATA_1 = 0x400, + CTUCANFD_TXTB4_DATA_2 = 0x404, + CTUCANFD_TXTB4_DATA_20 = 0x44c, +}; + +/* Control_registers memory region */ + +/* DEVICE_ID VERSION registers */ +#define REG_DEVICE_ID_DEVICE_ID GENMASK(15, 0) +#define REG_DEVICE_ID_VER_MINOR GENMASK(23, 16) +#define REG_DEVICE_ID_VER_MAJOR GENMASK(31, 24) + +/* MODE SETTINGS registers */ +#define REG_MODE_RST BIT(0) +#define REG_MODE_BMM BIT(1) +#define REG_MODE_STM BIT(2) +#define REG_MODE_AFM BIT(3) +#define REG_MODE_FDE BIT(4) +#define REG_MODE_ACF BIT(7) +#define REG_MODE_TSTM BIT(8) +#define REG_MODE_RTRLE BIT(16) +#define REG_MODE_RTRTH GENMASK(20, 17) +#define REG_MODE_ILBP BIT(21) +#define REG_MODE_ENA BIT(22) +#define REG_MODE_NISOFD BIT(23) +#define REG_MODE_PEX BIT(24) +#define REG_MODE_TBFBO BIT(25) +#define REG_MODE_FDRF BIT(26) + +/* STATUS registers */ +#define REG_STATUS_RXNE BIT(0) +#define REG_STATUS_DOR BIT(1) +#define REG_STATUS_TXNF BIT(2) +#define REG_STATUS_EFT BIT(3) +#define REG_STATUS_RXS BIT(4) +#define REG_STATUS_TXS BIT(5) +#define REG_STATUS_EWL BIT(6) +#define REG_STATUS_IDLE BIT(7) +#define REG_STATUS_PEXS BIT(8) + +/* COMMAND registers */ +#define REG_COMMAND_RRB BIT(2) +#define REG_COMMAND_CDO BIT(3) +#define REG_COMMAND_ERCRST BIT(4) +#define REG_COMMAND_RXFCRST BIT(5) +#define REG_COMMAND_TXFCRST BIT(6) +#define REG_COMMAND_CPEXS BIT(7) + +/* INT_STAT registers */ +#define REG_INT_STAT_RXI BIT(0) +#define REG_INT_STAT_TXI BIT(1) +#define REG_INT_STAT_EWLI BIT(2) +#define REG_INT_STAT_DOI BIT(3) +#define REG_INT_STAT_FCSI BIT(4) +#define REG_INT_STAT_ALI BIT(5) +#define REG_INT_STAT_BEI BIT(6) +#define REG_INT_STAT_OFI BIT(7) +#define REG_INT_STAT_RXFI BIT(8) +#define REG_INT_STAT_BSI BIT(9) +#define REG_INT_STAT_RBNEI BIT(10) +#define REG_INT_STAT_TXBHCI BIT(11) + +/* INT_ENA_SET registers */ +#define REG_INT_ENA_SET_INT_ENA_SET GENMASK(11, 0) + +/* INT_ENA_CLR registers */ +#define REG_INT_ENA_CLR_INT_ENA_CLR GENMASK(11, 0) + +/* INT_MASK_SET registers */ +#define REG_INT_MASK_SET_INT_MASK_SET GENMASK(11, 0) + +/* INT_MASK_CLR registers */ +#define REG_INT_MASK_CLR_INT_MASK_CLR GENMASK(11, 0) + +/* BTR registers */ +#define REG_BTR_PROP GENMASK(6, 0) +#define REG_BTR_PH1 GENMASK(12, 7) +#define REG_BTR_PH2 GENMASK(18, 13) +#define REG_BTR_BRP GENMASK(26, 19) +#define REG_BTR_SJW GENMASK(31, 27) + +/* BTR_FD registers */ +#define REG_BTR_FD_PROP_FD GENMASK(5, 0) +#define REG_BTR_FD_PH1_FD GENMASK(11, 7) +#define REG_BTR_FD_PH2_FD GENMASK(17, 13) +#define REG_BTR_FD_BRP_FD GENMASK(26, 19) +#define REG_BTR_FD_SJW_FD GENMASK(31, 27) + +/* EWL ERP FAULT_STATE registers */ +#define REG_EWL_EW_LIMIT GENMASK(7, 0) +#define REG_EWL_ERP_LIMIT GENMASK(15, 8) +#define REG_EWL_ERA BIT(16) +#define REG_EWL_ERP BIT(17) +#define REG_EWL_BOF BIT(18) + +/* REC TEC registers */ +#define REG_REC_REC_VAL GENMASK(8, 0) +#define REG_REC_TEC_VAL GENMASK(24, 16) + +/* ERR_NORM ERR_FD registers */ +#define REG_ERR_NORM_ERR_NORM_VAL GENMASK(15, 0) +#define REG_ERR_NORM_ERR_FD_VAL GENMASK(31, 16) + +/* CTR_PRES registers */ +#define REG_CTR_PRES_CTPV GENMASK(8, 0) +#define REG_CTR_PRES_PTX BIT(9) +#define REG_CTR_PRES_PRX BIT(10) +#define REG_CTR_PRES_ENORM BIT(11) +#define REG_CTR_PRES_EFD BIT(12) + +/* FILTER_A_MASK registers */ +#define REG_FILTER_A_MASK_BIT_MASK_A_VAL GENMASK(28, 0) + +/* FILTER_A_VAL registers */ +#define REG_FILTER_A_VAL_BIT_VAL_A_VAL GENMASK(28, 0) + +/* FILTER_B_MASK registers */ +#define REG_FILTER_B_MASK_BIT_MASK_B_VAL GENMASK(28, 0) + +/* FILTER_B_VAL registers */ +#define REG_FILTER_B_VAL_BIT_VAL_B_VAL GENMASK(28, 0) + +/* FILTER_C_MASK registers */ +#define REG_FILTER_C_MASK_BIT_MASK_C_VAL GENMASK(28, 0) + +/* FILTER_C_VAL registers */ +#define REG_FILTER_C_VAL_BIT_VAL_C_VAL GENMASK(28, 0) + +/* FILTER_RAN_LOW registers */ +#define REG_FILTER_RAN_LOW_BIT_RAN_LOW_VAL GENMASK(28, 0) + +/* FILTER_RAN_HIGH registers */ +#define REG_FILTER_RAN_HIGH_BIT_RAN_HIGH_VAL GENMASK(28, 0) + +/* FILTER_CONTROL FILTER_STATUS registers */ +#define REG_FILTER_CONTROL_FANB BIT(0) +#define REG_FILTER_CONTROL_FANE BIT(1) +#define REG_FILTER_CONTROL_FAFB BIT(2) +#define REG_FILTER_CONTROL_FAFE BIT(3) +#define REG_FILTER_CONTROL_FBNB BIT(4) +#define REG_FILTER_CONTROL_FBNE BIT(5) +#define REG_FILTER_CONTROL_FBFB BIT(6) +#define REG_FILTER_CONTROL_FBFE BIT(7) +#define REG_FILTER_CONTROL_FCNB BIT(8) +#define REG_FILTER_CONTROL_FCNE BIT(9) +#define REG_FILTER_CONTROL_FCFB BIT(10) +#define REG_FILTER_CONTROL_FCFE BIT(11) +#define REG_FILTER_CONTROL_FRNB BIT(12) +#define REG_FILTER_CONTROL_FRNE BIT(13) +#define REG_FILTER_CONTROL_FRFB BIT(14) +#define REG_FILTER_CONTROL_FRFE BIT(15) +#define REG_FILTER_CONTROL_SFA BIT(16) +#define REG_FILTER_CONTROL_SFB BIT(17) +#define REG_FILTER_CONTROL_SFC BIT(18) +#define REG_FILTER_CONTROL_SFR BIT(19) + +/* RX_MEM_INFO registers */ +#define REG_RX_MEM_INFO_RX_BUFF_SIZE GENMASK(12, 0) +#define REG_RX_MEM_INFO_RX_MEM_FREE GENMASK(28, 16) + +/* RX_POINTERS registers */ +#define REG_RX_POINTERS_RX_WPP GENMASK(11, 0) +#define REG_RX_POINTERS_RX_RPP GENMASK(27, 16) + +/* RX_STATUS RX_SETTINGS registers */ +#define REG_RX_STATUS_RXE BIT(0) +#define REG_RX_STATUS_RXF BIT(1) +#define REG_RX_STATUS_RXMOF BIT(2) +#define REG_RX_STATUS_RXFRC GENMASK(14, 4) +#define REG_RX_STATUS_RTSOP BIT(16) + +/* RX_DATA registers */ +#define REG_RX_DATA_RX_DATA GENMASK(31, 0) + +/* TX_STATUS registers */ +#define REG_TX_STATUS_TX1S GENMASK(3, 0) +#define REG_TX_STATUS_TX2S GENMASK(7, 4) +#define REG_TX_STATUS_TX3S GENMASK(11, 8) +#define REG_TX_STATUS_TX4S GENMASK(15, 12) + +/* TX_COMMAND registers */ +#define REG_TX_COMMAND_TXCE BIT(0) +#define REG_TX_COMMAND_TXCR BIT(1) +#define REG_TX_COMMAND_TXCA BIT(2) +#define REG_TX_COMMAND_TXB1 BIT(8) +#define REG_TX_COMMAND_TXB2 BIT(9) +#define REG_TX_COMMAND_TXB3 BIT(10) +#define REG_TX_COMMAND_TXB4 BIT(11) + +/* TX_PRIORITY registers */ +#define REG_TX_PRIORITY_TXT1P GENMASK(2, 0) +#define REG_TX_PRIORITY_TXT2P GENMASK(6, 4) +#define REG_TX_PRIORITY_TXT3P GENMASK(10, 8) +#define REG_TX_PRIORITY_TXT4P GENMASK(14, 12) + +/* ERR_CAPT ALC registers */ +#define REG_ERR_CAPT_ERR_POS GENMASK(4, 0) +#define REG_ERR_CAPT_ERR_TYPE GENMASK(7, 5) +#define REG_ERR_CAPT_ALC_BIT GENMASK(20, 16) +#define REG_ERR_CAPT_ALC_ID_FIELD GENMASK(23, 21) + +/* TRV_DELAY SSP_CFG registers */ +#define REG_TRV_DELAY_TRV_DELAY_VALUE GENMASK(6, 0) +#define REG_TRV_DELAY_SSP_OFFSET GENMASK(23, 16) +#define REG_TRV_DELAY_SSP_SRC GENMASK(25, 24) + +/* RX_FR_CTR registers */ +#define REG_RX_FR_CTR_RX_FR_CTR_VAL GENMASK(31, 0) + +/* TX_FR_CTR registers */ +#define REG_TX_FR_CTR_TX_FR_CTR_VAL GENMASK(31, 0) + +/* DEBUG_REGISTER registers */ +#define REG_DEBUG_REGISTER_STUFF_COUNT GENMASK(2, 0) +#define REG_DEBUG_REGISTER_DESTUFF_COUNT GENMASK(5, 3) +#define REG_DEBUG_REGISTER_PC_ARB BIT(6) +#define REG_DEBUG_REGISTER_PC_CON BIT(7) +#define REG_DEBUG_REGISTER_PC_DAT BIT(8) +#define REG_DEBUG_REGISTER_PC_STC BIT(9) +#define REG_DEBUG_REGISTER_PC_CRC BIT(10) +#define REG_DEBUG_REGISTER_PC_CRCD BIT(11) +#define REG_DEBUG_REGISTER_PC_ACK BIT(12) +#define REG_DEBUG_REGISTER_PC_ACKD BIT(13) +#define REG_DEBUG_REGISTER_PC_EOF BIT(14) +#define REG_DEBUG_REGISTER_PC_INT BIT(15) +#define REG_DEBUG_REGISTER_PC_SUSP BIT(16) +#define REG_DEBUG_REGISTER_PC_OVR BIT(17) +#define REG_DEBUG_REGISTER_PC_SOF BIT(18) + +/* YOLO_REG registers */ +#define REG_YOLO_REG_YOLO_VAL GENMASK(31, 0) + +/* TIMESTAMP_LOW registers */ +#define REG_TIMESTAMP_LOW_TIMESTAMP_LOW GENMASK(31, 0) + +/* TIMESTAMP_HIGH registers */ +#define REG_TIMESTAMP_HIGH_TIMESTAMP_HIGH GENMASK(31, 0) + +#endif diff --git a/drivers/net/can/ctucanfd/ctucanfd_pci.c b/drivers/net/can/ctucanfd/ctucanfd_pci.c new file mode 100644 index 000000000000..8f2956a8ae43 --- /dev/null +++ b/drivers/net/can/ctucanfd/ctucanfd_pci.c @@ -0,0 +1,294 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/******************************************************************************* + * + * CTU CAN FD IP Core + * + * Copyright (C) 2015-2018 Ondrej Ille <ondrej.ille@gmail.com> FEE CTU + * Copyright (C) 2018-2021 Ondrej Ille <ondrej.ille@gmail.com> self-funded + * Copyright (C) 2018-2019 Martin Jerabek <martin.jerabek01@gmail.com> FEE CTU + * Copyright (C) 2018-2022 Pavel Pisa <pisa@cmp.felk.cvut.cz> FEE CTU/self-funded + * + * Project advisors: + * Jiri Novak <jnovak@fel.cvut.cz> + * Pavel Pisa <pisa@cmp.felk.cvut.cz> + * + * 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/module.h> +#include <linux/pci.h> + +#include "ctucanfd.h" + +#ifndef PCI_DEVICE_DATA +#define PCI_DEVICE_DATA(vend, dev, data) \ +.vendor = PCI_VENDOR_ID_##vend, \ +.device = PCI_DEVICE_ID_##vend##_##dev, \ +.subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, 0, 0, \ +.driver_data = (kernel_ulong_t)(data) +#endif + +#ifndef PCI_VENDOR_ID_TEDIA +#define PCI_VENDOR_ID_TEDIA 0x1760 +#endif + +#ifndef PCI_DEVICE_ID_TEDIA_CTUCAN_VER21 +#define PCI_DEVICE_ID_TEDIA_CTUCAN_VER21 0xff00 +#endif + +#define CTUCAN_BAR0_CTUCAN_ID 0x0000 +#define CTUCAN_BAR0_CRA_BASE 0x4000 +#define CYCLONE_IV_CRA_A2P_IE (0x0050) + +#define CTUCAN_WITHOUT_CTUCAN_ID 0 +#define CTUCAN_WITH_CTUCAN_ID 1 + +struct ctucan_pci_board_data { + void __iomem *bar0_base; + void __iomem *cra_base; + void __iomem *bar1_base; + struct list_head ndev_list_head; + int use_msi; +}; + +static struct ctucan_pci_board_data *ctucan_pci_get_bdata(struct pci_dev *pdev) +{ + return (struct ctucan_pci_board_data *)pci_get_drvdata(pdev); +} + +static void ctucan_pci_set_drvdata(struct device *dev, + struct net_device *ndev) +{ + struct pci_dev *pdev = container_of(dev, struct pci_dev, dev); + struct ctucan_priv *priv = netdev_priv(ndev); + struct ctucan_pci_board_data *bdata = ctucan_pci_get_bdata(pdev); + + list_add(&priv->peers_on_pdev, &bdata->ndev_list_head); + priv->irq_flags = IRQF_SHARED; +} + +/** + * ctucan_pci_probe - PCI registration call + * @pdev: Handle to the pci device structure + * @ent: Pointer to the entry from ctucan_pci_tbl + * + * This function does all the memory allocation and registration for the CAN + * device. + * + * Return: 0 on success and failure value on error + */ +static int ctucan_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct device *dev = &pdev->dev; + unsigned long driver_data = ent->driver_data; + struct ctucan_pci_board_data *bdata; + void __iomem *addr; + void __iomem *cra_addr; + void __iomem *bar0_base; + u32 cra_a2p_ie; + u32 ctucan_id = 0; + int ret; + unsigned int ntxbufs; + unsigned int num_cores = 1; + unsigned int core_i = 0; + int irq; + int msi_ok = 0; + + ret = pci_enable_device(pdev); + if (ret) { + dev_err(dev, "pci_enable_device FAILED\n"); + goto err; + } + + ret = pci_request_regions(pdev, KBUILD_MODNAME); + if (ret) { + dev_err(dev, "pci_request_regions FAILED\n"); + goto err_disable_device; + } + + ret = pci_enable_msi(pdev); + if (!ret) { + dev_info(dev, "MSI enabled\n"); + pci_set_master(pdev); + msi_ok = 1; + } + + dev_info(dev, "ctucan BAR0 0x%08llx 0x%08llx\n", + (long long)pci_resource_start(pdev, 0), + (long long)pci_resource_len(pdev, 0)); + + dev_info(dev, "ctucan BAR1 0x%08llx 0x%08llx\n", + (long long)pci_resource_start(pdev, 1), + (long long)pci_resource_len(pdev, 1)); + + addr = pci_iomap(pdev, 1, pci_resource_len(pdev, 1)); + if (!addr) { + dev_err(dev, "PCI BAR 1 cannot be mapped\n"); + ret = -ENOMEM; + goto err_release_regions; + } + + /* Cyclone IV PCI Express Control Registers Area */ + bar0_base = pci_iomap(pdev, 0, pci_resource_len(pdev, 0)); + if (!bar0_base) { + dev_err(dev, "PCI BAR 0 cannot be mapped\n"); + ret = -EIO; + goto err_pci_iounmap_bar1; + } + + if (driver_data == CTUCAN_WITHOUT_CTUCAN_ID) { + cra_addr = bar0_base; + num_cores = 2; + } else { + cra_addr = bar0_base + CTUCAN_BAR0_CRA_BASE; + ctucan_id = ioread32(bar0_base + CTUCAN_BAR0_CTUCAN_ID); + dev_info(dev, "ctucan_id 0x%08lx\n", (unsigned long)ctucan_id); + num_cores = ctucan_id & 0xf; + } + + irq = pdev->irq; + + ntxbufs = 4; + + bdata = kzalloc(sizeof(*bdata), GFP_KERNEL); + if (!bdata) { + ret = -ENOMEM; + goto err_pci_iounmap_bar0; + } + + INIT_LIST_HEAD(&bdata->ndev_list_head); + bdata->bar0_base = bar0_base; + bdata->cra_base = cra_addr; + bdata->bar1_base = addr; + bdata->use_msi = msi_ok; + + pci_set_drvdata(pdev, bdata); + + ret = ctucan_probe_common(dev, addr, irq, ntxbufs, 100000000, + 0, ctucan_pci_set_drvdata); + if (ret < 0) + goto err_free_board; + + core_i++; + + while (core_i < num_cores) { + addr += 0x4000; + ret = ctucan_probe_common(dev, addr, irq, ntxbufs, 100000000, + 0, ctucan_pci_set_drvdata); + if (ret < 0) { + dev_info(dev, "CTU CAN FD core %d initialization failed\n", + core_i); + break; + } + core_i++; + } + + /* enable interrupt in + * Avalon-MM to PCI Express Interrupt Enable Register + */ + cra_a2p_ie = ioread32(cra_addr + CYCLONE_IV_CRA_A2P_IE); + dev_info(dev, "cra_a2p_ie 0x%08x\n", cra_a2p_ie); + cra_a2p_ie |= 1; + iowrite32(cra_a2p_ie, cra_addr + CYCLONE_IV_CRA_A2P_IE); + cra_a2p_ie = ioread32(cra_addr + CYCLONE_IV_CRA_A2P_IE); + dev_info(dev, "cra_a2p_ie 0x%08x\n", cra_a2p_ie); + + return 0; + +err_free_board: + pci_set_drvdata(pdev, NULL); + kfree(bdata); +err_pci_iounmap_bar0: + pci_iounmap(pdev, cra_addr); +err_pci_iounmap_bar1: + pci_iounmap(pdev, addr); +err_release_regions: + if (msi_ok) { + pci_disable_msi(pdev); + pci_clear_master(pdev); + } + pci_release_regions(pdev); +err_disable_device: + pci_disable_device(pdev); +err: + return ret; +} + +/** + * ctucan_pci_remove - Unregister the device after releasing the resources + * @pdev: Handle to the pci device structure + * + * This function frees all the resources allocated to the device. + * Return: 0 always + */ +static void ctucan_pci_remove(struct pci_dev *pdev) +{ + struct net_device *ndev; + struct ctucan_priv *priv = NULL; + struct ctucan_pci_board_data *bdata = ctucan_pci_get_bdata(pdev); + + dev_dbg(&pdev->dev, "ctucan_remove"); + + if (!bdata) { + dev_err(&pdev->dev, "%s: no list of devices\n", __func__); + return; + } + + /* disable interrupt in + * Avalon-MM to PCI Express Interrupt Enable Register + */ + if (bdata->cra_base) + iowrite32(0, bdata->cra_base + CYCLONE_IV_CRA_A2P_IE); + + while ((priv = list_first_entry_or_null(&bdata->ndev_list_head, struct ctucan_priv, + peers_on_pdev)) != NULL) { + ndev = priv->can.dev; + + unregister_candev(ndev); + + netif_napi_del(&priv->napi); + + list_del_init(&priv->peers_on_pdev); + free_candev(ndev); + } + + pci_iounmap(pdev, bdata->bar1_base); + + if (bdata->use_msi) { + pci_disable_msi(pdev); + pci_clear_master(pdev); + } + + pci_release_regions(pdev); + pci_disable_device(pdev); + + pci_iounmap(pdev, bdata->bar0_base); + + pci_set_drvdata(pdev, NULL); + kfree(bdata); +} + +static SIMPLE_DEV_PM_OPS(ctucan_pci_pm_ops, ctucan_suspend, ctucan_resume); + +static const struct pci_device_id ctucan_pci_tbl[] = { + {PCI_DEVICE_DATA(TEDIA, CTUCAN_VER21, + CTUCAN_WITH_CTUCAN_ID)}, + {}, +}; + +static struct pci_driver ctucan_pci_driver = { + .name = KBUILD_MODNAME, + .id_table = ctucan_pci_tbl, + .probe = ctucan_pci_probe, + .remove = ctucan_pci_remove, + .driver.pm = &ctucan_pci_pm_ops, +}; + +module_pci_driver(ctucan_pci_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Pavel Pisa <pisa@cmp.felk.cvut.cz>"); +MODULE_DESCRIPTION("CTU CAN FD for PCI bus"); diff --git a/drivers/net/can/ctucanfd/ctucanfd_platform.c b/drivers/net/can/ctucanfd/ctucanfd_platform.c new file mode 100644 index 000000000000..89d54c2151e1 --- /dev/null +++ b/drivers/net/can/ctucanfd/ctucanfd_platform.c @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/******************************************************************************* + * + * CTU CAN FD IP Core + * + * Copyright (C) 2015-2018 Ondrej Ille <ondrej.ille@gmail.com> FEE CTU + * Copyright (C) 2018-2021 Ondrej Ille <ondrej.ille@gmail.com> self-funded + * Copyright (C) 2018-2019 Martin Jerabek <martin.jerabek01@gmail.com> FEE CTU + * Copyright (C) 2018-2022 Pavel Pisa <pisa@cmp.felk.cvut.cz> FEE CTU/self-funded + * + * Project advisors: + * Jiri Novak <jnovak@fel.cvut.cz> + * Pavel Pisa <pisa@cmp.felk.cvut.cz> + * + * 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/module.h> +#include <linux/netdevice.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> + +#include "ctucanfd.h" + +#define DRV_NAME "ctucanfd" + +static void ctucan_platform_set_drvdata(struct device *dev, + struct net_device *ndev) +{ + struct platform_device *pdev = container_of(dev, struct platform_device, + dev); + + platform_set_drvdata(pdev, ndev); +} + +/** + * ctucan_platform_probe - Platform registration call + * @pdev: Handle to the platform device structure + * + * This function does all the memory allocation and registration for the CAN + * device. + * + * Return: 0 on success and failure value on error + */ +static int ctucan_platform_probe(struct platform_device *pdev) +{ + struct resource *res; /* IO mem resources */ + struct device *dev = &pdev->dev; + void __iomem *addr; + int ret; + unsigned int ntxbufs; + int irq; + + /* Get the virtual base address for the device */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + addr = devm_ioremap_resource(dev, res); + if (IS_ERR(addr)) { + dev_err(dev, "Cannot remap address.\n"); + ret = PTR_ERR(addr); + goto err; + } + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + ret = irq; + goto err; + } + + /* Number of tx bufs might be change in HW for future. If so, + * it will be passed as property via device tree + */ + ntxbufs = 4; + ret = ctucan_probe_common(dev, addr, irq, ntxbufs, 0, + 1, ctucan_platform_set_drvdata); + + if (ret < 0) + platform_set_drvdata(pdev, NULL); + +err: + return ret; +} + +/** + * ctucan_platform_remove - Unregister the device after releasing the resources + * @pdev: Handle to the platform device structure + * + * This function frees all the resources allocated to the device. + * Return: 0 always + */ +static int ctucan_platform_remove(struct platform_device *pdev) +{ + struct net_device *ndev = platform_get_drvdata(pdev); + struct ctucan_priv *priv = netdev_priv(ndev); + + netdev_dbg(ndev, "ctucan_remove"); + + unregister_candev(ndev); + pm_runtime_disable(&pdev->dev); + netif_napi_del(&priv->napi); + free_candev(ndev); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(ctucan_platform_pm_ops, ctucan_suspend, ctucan_resume); + +/* Match table for OF platform binding */ +static const struct of_device_id ctucan_of_match[] = { + { .compatible = "ctu,ctucanfd-2", }, + { .compatible = "ctu,ctucanfd", }, + { /* end of list */ }, +}; +MODULE_DEVICE_TABLE(of, ctucan_of_match); + +static struct platform_driver ctucanfd_driver = { + .probe = ctucan_platform_probe, + .remove = ctucan_platform_remove, + .driver = { + .name = DRV_NAME, + .pm = &ctucan_platform_pm_ops, + .of_match_table = ctucan_of_match, + }, +}; + +module_platform_driver(ctucanfd_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Martin Jerabek"); +MODULE_DESCRIPTION("CTU CAN FD for platform"); diff --git a/drivers/net/can/dev/Makefile b/drivers/net/can/dev/Makefile index 3e2e207861fc..af2901db473c 100644 --- a/drivers/net/can/dev/Makefile +++ b/drivers/net/can/dev/Makefile @@ -7,5 +7,3 @@ can-dev-y += length.o can-dev-y += netlink.o can-dev-y += rx-offload.o can-dev-y += skb.o - -can-dev-$(CONFIG_CAN_LEDS) += led.o diff --git a/drivers/net/can/dev/bittiming.c b/drivers/net/can/dev/bittiming.c index 2103bcca9012..c1e76f0a5064 100644 --- a/drivers/net/can/dev/bittiming.c +++ b/drivers/net/can/dev/bittiming.c @@ -116,7 +116,7 @@ int can_calc_bittiming(const struct net_device *dev, struct can_bittiming *bt, can_update_sample_point(btc, sample_point_nominal, tseg / 2, &tseg1, &tseg2, &sample_point_error); - if (sample_point_error > best_sample_point_error) + if (sample_point_error >= best_sample_point_error) continue; best_sample_point_error = sample_point_error; diff --git a/drivers/net/can/dev/dev.c b/drivers/net/can/dev/dev.c index e7ab45f1c43b..96c9d9db00cf 100644 --- a/drivers/net/can/dev/dev.c +++ b/drivers/net/can/dev/dev.c @@ -14,7 +14,6 @@ #include <linux/can/can-ml.h> #include <linux/can/dev.h> #include <linux/can/skb.h> -#include <linux/can/led.h> #include <linux/gpio/consumer.h> #include <linux/of.h> @@ -512,8 +511,6 @@ static __init int can_dev_init(void) { int err; - can_led_notifier_init(); - err = can_netlink_register(); if (!err) pr_info(MOD_DESC "\n"); @@ -525,8 +522,6 @@ module_init(can_dev_init); static __exit void can_dev_exit(void) { can_netlink_unregister(); - - can_led_notifier_exit(); } module_exit(can_dev_exit); diff --git a/drivers/net/can/dev/rx-offload.c b/drivers/net/can/dev/rx-offload.c index 7f80d8e1e750..a32a01c172d4 100644 --- a/drivers/net/can/dev/rx-offload.c +++ b/drivers/net/can/dev/rx-offload.c @@ -70,8 +70,6 @@ static int can_rx_offload_napi_poll(struct napi_struct *napi, int quota) napi_reschedule(&offload->napi); } - can_led_event(offload->dev, CAN_LED_EVENT_RX); - return work_done; } @@ -221,7 +219,7 @@ int can_rx_offload_irq_offload_fifo(struct can_rx_offload *offload) } EXPORT_SYMBOL_GPL(can_rx_offload_irq_offload_fifo); -int can_rx_offload_queue_sorted(struct can_rx_offload *offload, +int can_rx_offload_queue_timestamp(struct can_rx_offload *offload, struct sk_buff *skb, u32 timestamp) { struct can_rx_offload_cb *cb; @@ -240,7 +238,7 @@ int can_rx_offload_queue_sorted(struct can_rx_offload *offload, return 0; } -EXPORT_SYMBOL_GPL(can_rx_offload_queue_sorted); +EXPORT_SYMBOL_GPL(can_rx_offload_queue_timestamp); unsigned int can_rx_offload_get_echo_skb(struct can_rx_offload *offload, unsigned int idx, u32 timestamp, @@ -256,7 +254,7 @@ unsigned int can_rx_offload_get_echo_skb(struct can_rx_offload *offload, if (!skb) return 0; - err = can_rx_offload_queue_sorted(offload, skb, timestamp); + err = can_rx_offload_queue_timestamp(offload, skb, timestamp); if (err) { stats->rx_errors++; stats->tx_fifo_errors++; @@ -337,7 +335,8 @@ static int can_rx_offload_init_queue(struct net_device *dev, skb_queue_head_init(&offload->skb_queue); __skb_queue_head_init(&offload->skb_irq_queue); - netif_napi_add(dev, &offload->napi, can_rx_offload_napi_poll, weight); + netif_napi_add_weight(dev, &offload->napi, can_rx_offload_napi_poll, + weight); dev_dbg(dev->dev.parent, "%s: skb_queue_len_max=%d\n", __func__, offload->skb_queue_len_max); diff --git a/drivers/net/can/flexcan/flexcan-core.c b/drivers/net/can/flexcan/flexcan-core.c index 74d7fcbfd065..d060088047f1 100644 --- a/drivers/net/can/flexcan/flexcan-core.c +++ b/drivers/net/can/flexcan/flexcan-core.c @@ -14,7 +14,6 @@ #include <linux/can.h> #include <linux/can/dev.h> #include <linux/can/error.h> -#include <linux/can/led.h> #include <linux/clk.h> #include <linux/delay.h> #include <linux/firmware/imx/sci.h> @@ -723,11 +722,9 @@ static int flexcan_get_berr_counter(const struct net_device *dev, const struct flexcan_priv *priv = netdev_priv(dev); int err; - err = pm_runtime_get_sync(priv->dev); - if (err < 0) { - pm_runtime_put_noidle(priv->dev); + err = pm_runtime_resume_and_get(priv->dev); + if (err < 0) return err; - } err = __flexcan_get_berr_counter(dev, bec); @@ -845,7 +842,7 @@ static void flexcan_irq_bus_err(struct net_device *dev, u32 reg_esr) if (tx_errors) dev->stats.tx_errors++; - err = can_rx_offload_queue_sorted(&priv->offload, skb, timestamp); + err = can_rx_offload_queue_timestamp(&priv->offload, skb, timestamp); if (err) dev->stats.rx_fifo_errors++; } @@ -892,7 +889,7 @@ static void flexcan_irq_state(struct net_device *dev, u32 reg_esr) if (unlikely(new_state == CAN_STATE_BUS_OFF)) can_bus_off(dev); - err = can_rx_offload_queue_sorted(&priv->offload, skb, timestamp); + err = can_rx_offload_queue_timestamp(&priv->offload, skb, timestamp); if (err) dev->stats.rx_fifo_errors++; } @@ -1083,7 +1080,6 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id) can_rx_offload_get_echo_skb(&priv->offload, 0, reg_ctrl << 16, NULL); stats->tx_packets++; - can_led_event(dev, CAN_LED_EVENT_TX); /* after sending a RTR frame MB is in RX mode */ priv->write(FLEXCAN_MB_CODE_TX_INACTIVE, @@ -1700,11 +1696,9 @@ static int flexcan_open(struct net_device *dev) return -EINVAL; } - err = pm_runtime_get_sync(priv->dev); - if (err < 0) { - pm_runtime_put_noidle(priv->dev); + err = pm_runtime_resume_and_get(priv->dev); + if (err < 0) return err; - } err = open_candev(dev); if (err) @@ -1742,8 +1736,6 @@ static int flexcan_open(struct net_device *dev) flexcan_chip_interrupts_enable(dev); - can_led_event(dev, CAN_LED_EVENT_OPEN); - netif_start_queue(dev); return 0; @@ -1789,8 +1781,6 @@ static int flexcan_close(struct net_device *dev) pm_runtime_put(priv->dev); - can_led_event(dev, CAN_LED_EVENT_STOP); - return 0; } @@ -2193,7 +2183,6 @@ static int flexcan_probe(struct platform_device *pdev) } of_can_transceiver(dev); - devm_can_led_init(dev); return 0; diff --git a/drivers/net/can/grcan.c b/drivers/net/can/grcan.c index 5215bd9b2c80..76df4807d366 100644 --- a/drivers/net/can/grcan.c +++ b/drivers/net/can/grcan.c @@ -1609,7 +1609,7 @@ static int grcan_setup_netdev(struct platform_device *ofdev, timer_setup(&priv->hang_timer, grcan_initiate_running_reset, 0); } - netif_napi_add(dev, &priv->napi, grcan_poll, GRCAN_NAPI_WEIGHT); + netif_napi_add_weight(dev, &priv->napi, grcan_poll, GRCAN_NAPI_WEIGHT); SET_NETDEV_DEV(dev, &ofdev->dev); dev_info(&ofdev->dev, "regs=0x%p, irq=%d, clock=%d\n", diff --git a/drivers/net/can/ifi_canfd/ifi_canfd.c b/drivers/net/can/ifi_canfd/ifi_canfd.c index b0a3473f211d..968ed6d7316b 100644 --- a/drivers/net/can/ifi_canfd/ifi_canfd.c +++ b/drivers/net/can/ifi_canfd/ifi_canfd.c @@ -345,9 +345,6 @@ static int ifi_canfd_do_rx_poll(struct net_device *ndev, int quota) rxst = readl(priv->base + IFI_CANFD_RXSTCMD); } - if (pkts) - can_led_event(ndev, CAN_LED_EVENT_RX); - return pkts; } @@ -626,7 +623,6 @@ static irqreturn_t ifi_canfd_isr(int irq, void *dev_id) if (isr & IFI_CANFD_INTERRUPT_TXFIFO_REMOVE) { stats->tx_bytes += can_get_echo_skb(ndev, 0, NULL); stats->tx_packets++; - can_led_event(ndev, CAN_LED_EVENT_TX); } if (isr & tx_irq_mask) @@ -830,7 +826,6 @@ static int ifi_canfd_open(struct net_device *ndev) ifi_canfd_start(ndev); - can_led_event(ndev, CAN_LED_EVENT_OPEN); napi_enable(&priv->napi); netif_start_queue(ndev); @@ -853,8 +848,6 @@ static int ifi_canfd_close(struct net_device *ndev) close_candev(ndev); - can_led_event(ndev, CAN_LED_EVENT_STOP); - return 0; } @@ -1004,8 +997,6 @@ static int ifi_canfd_plat_probe(struct platform_device *pdev) goto err_reg; } - devm_can_led_init(ndev); - dev_info(dev, "Driver registered: regs=%p, irq=%d, clock=%d\n", priv->base, ndev->irq, priv->can.clock.freq); diff --git a/drivers/net/can/janz-ican3.c b/drivers/net/can/janz-ican3.c index 808c105cf8f7..35bfb82d6929 100644 --- a/drivers/net/can/janz-ican3.c +++ b/drivers/net/can/janz-ican3.c @@ -1910,7 +1910,7 @@ static int ican3_probe(struct platform_device *pdev) mod = netdev_priv(ndev); mod->ndev = ndev; mod->num = pdata->modno; - netif_napi_add(ndev, &mod->napi, ican3_napi, ICAN3_RX_BUFFERS); + netif_napi_add_weight(ndev, &mod->napi, ican3_napi, ICAN3_RX_BUFFERS); skb_queue_head_init(&mod->echoq); spin_lock_init(&mod->lock); init_completion(&mod->termination_comp); diff --git a/drivers/net/can/led.c b/drivers/net/can/led.c deleted file mode 100644 index db14897f8e16..000000000000 --- a/drivers/net/can/led.c +++ /dev/null @@ -1,140 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright 2012, Fabio Baltieri <fabio.baltieri@gmail.com> - * Copyright 2012, Kurt Van Dijck <kurt.van.dijck@eia.be> - */ - -#include <linux/module.h> -#include <linux/device.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/netdevice.h> -#include <linux/can/dev.h> - -#include <linux/can/led.h> - -static unsigned long led_delay = 50; -module_param(led_delay, ulong, 0644); -MODULE_PARM_DESC(led_delay, - "blink delay time for activity leds (msecs, default: 50)."); - -/* Trigger a LED event in response to a CAN device event */ -void can_led_event(struct net_device *netdev, enum can_led_event event) -{ - struct can_priv *priv = netdev_priv(netdev); - - switch (event) { - case CAN_LED_EVENT_OPEN: - led_trigger_event(priv->tx_led_trig, LED_FULL); - led_trigger_event(priv->rx_led_trig, LED_FULL); - led_trigger_event(priv->rxtx_led_trig, LED_FULL); - break; - case CAN_LED_EVENT_STOP: - led_trigger_event(priv->tx_led_trig, LED_OFF); - led_trigger_event(priv->rx_led_trig, LED_OFF); - led_trigger_event(priv->rxtx_led_trig, LED_OFF); - break; - case CAN_LED_EVENT_TX: - if (led_delay) { - led_trigger_blink_oneshot(priv->tx_led_trig, - &led_delay, &led_delay, 1); - led_trigger_blink_oneshot(priv->rxtx_led_trig, - &led_delay, &led_delay, 1); - } - break; - case CAN_LED_EVENT_RX: - if (led_delay) { - led_trigger_blink_oneshot(priv->rx_led_trig, - &led_delay, &led_delay, 1); - led_trigger_blink_oneshot(priv->rxtx_led_trig, - &led_delay, &led_delay, 1); - } - break; - } -} -EXPORT_SYMBOL_GPL(can_led_event); - -static void can_led_release(struct device *gendev, void *res) -{ - struct can_priv *priv = netdev_priv(to_net_dev(gendev)); - - led_trigger_unregister_simple(priv->tx_led_trig); - led_trigger_unregister_simple(priv->rx_led_trig); - led_trigger_unregister_simple(priv->rxtx_led_trig); -} - -/* Register CAN LED triggers for a CAN device - * - * This is normally called from a driver's probe function - */ -void devm_can_led_init(struct net_device *netdev) -{ - struct can_priv *priv = netdev_priv(netdev); - void *res; - - res = devres_alloc(can_led_release, 0, GFP_KERNEL); - if (!res) { - netdev_err(netdev, "cannot register LED triggers\n"); - return; - } - - snprintf(priv->tx_led_trig_name, sizeof(priv->tx_led_trig_name), - "%s-tx", netdev->name); - snprintf(priv->rx_led_trig_name, sizeof(priv->rx_led_trig_name), - "%s-rx", netdev->name); - snprintf(priv->rxtx_led_trig_name, sizeof(priv->rxtx_led_trig_name), - "%s-rxtx", netdev->name); - - led_trigger_register_simple(priv->tx_led_trig_name, - &priv->tx_led_trig); - led_trigger_register_simple(priv->rx_led_trig_name, - &priv->rx_led_trig); - led_trigger_register_simple(priv->rxtx_led_trig_name, - &priv->rxtx_led_trig); - - devres_add(&netdev->dev, res); -} -EXPORT_SYMBOL_GPL(devm_can_led_init); - -/* NETDEV rename notifier to rename the associated led triggers too */ -static int can_led_notifier(struct notifier_block *nb, unsigned long msg, - void *ptr) -{ - struct net_device *netdev = netdev_notifier_info_to_dev(ptr); - struct can_priv *priv = safe_candev_priv(netdev); - char name[CAN_LED_NAME_SZ]; - - if (!priv) - return NOTIFY_DONE; - - if (!priv->tx_led_trig || !priv->rx_led_trig || !priv->rxtx_led_trig) - return NOTIFY_DONE; - - if (msg == NETDEV_CHANGENAME) { - snprintf(name, sizeof(name), "%s-tx", netdev->name); - led_trigger_rename_static(name, priv->tx_led_trig); - - snprintf(name, sizeof(name), "%s-rx", netdev->name); - led_trigger_rename_static(name, priv->rx_led_trig); - - snprintf(name, sizeof(name), "%s-rxtx", netdev->name); - led_trigger_rename_static(name, priv->rxtx_led_trig); - } - - return NOTIFY_DONE; -} - -/* notifier block for netdevice event */ -static struct notifier_block can_netdev_notifier __read_mostly = { - .notifier_call = can_led_notifier, -}; - -int __init can_led_notifier_init(void) -{ - return register_netdevice_notifier(&can_netdev_notifier); -} - -void __exit can_led_notifier_exit(void) -{ - unregister_netdevice_notifier(&can_netdev_notifier); -} diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c index 088bb1bcf1ef..5d0c82d8b9a9 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c @@ -77,9 +77,6 @@ enum m_can_reg { M_CAN_TXEFA = 0xf8, }; -/* napi related */ -#define M_CAN_NAPI_WEIGHT 64 - /* message ram configuration data length */ #define MRAM_CFG_LEN 8 @@ -464,7 +461,7 @@ static void m_can_receive_skb(struct m_can_classdev *cdev, struct net_device_stats *stats = &cdev->net->stats; int err; - err = can_rx_offload_queue_sorted(&cdev->offload, skb, + err = can_rx_offload_queue_timestamp(&cdev->offload, skb, timestamp); if (err) stats->rx_fifo_errors++; @@ -568,9 +565,6 @@ static int m_can_do_rx_poll(struct net_device *dev, int quota) rxfs = m_can_read(cdev, M_CAN_RXF0S); } - if (pkts) - can_led_event(dev, CAN_LED_EVENT_RX); - return pkts; } @@ -951,7 +945,7 @@ static int m_can_rx_peripheral(struct net_device *dev) struct m_can_classdev *cdev = netdev_priv(dev); int work_done; - work_done = m_can_rx_handler(dev, M_CAN_NAPI_WEIGHT); + work_done = m_can_rx_handler(dev, NAPI_POLL_WEIGHT); /* Don't re-enable interrupts if the driver had a fatal error * (e.g., FIFO read failure). @@ -1090,8 +1084,6 @@ static irqreturn_t m_can_isr(int irq, void *dev_id) if (cdev->is_peripheral) timestamp = m_can_get_timestamp(cdev); m_can_tx_update_stats(cdev, 0, timestamp); - - can_led_event(dev, CAN_LED_EVENT_TX); netif_wake_queue(dev); } } else { @@ -1100,7 +1092,6 @@ static irqreturn_t m_can_isr(int irq, void *dev_id) if (m_can_echo_tx_event(dev) != 0) goto out_fail; - can_led_event(dev, CAN_LED_EVENT_TX); if (netif_queue_stopped(dev) && !m_can_tx_fifo_full(cdev)) netif_wake_queue(dev); @@ -1474,7 +1465,7 @@ static int m_can_dev_setup(struct m_can_classdev *cdev) if (!cdev->is_peripheral) netif_napi_add(dev, &cdev->napi, - m_can_poll, M_CAN_NAPI_WEIGHT); + m_can_poll, NAPI_POLL_WEIGHT); /* Shared properties of all M_CAN versions */ cdev->version = m_can_version; @@ -1565,7 +1556,6 @@ static int m_can_close(struct net_device *dev) can_rx_offload_disable(&cdev->offload); close_candev(dev); - can_led_event(dev, CAN_LED_EVENT_STOP); phy_power_off(cdev->transceiver); @@ -1809,8 +1799,6 @@ static int m_can_open(struct net_device *dev) /* start the m_can controller */ m_can_start(dev); - can_led_event(dev, CAN_LED_EVENT_OPEN); - if (!cdev->is_peripheral) napi_enable(&cdev->napi); @@ -1982,7 +1970,7 @@ int m_can_class_register(struct m_can_classdev *cdev) if (cdev->is_peripheral) { ret = can_rx_offload_add_manual(cdev->net, &cdev->offload, - M_CAN_NAPI_WEIGHT); + NAPI_POLL_WEIGHT); if (ret) goto clk_disable; } @@ -1998,8 +1986,6 @@ int m_can_class_register(struct m_can_classdev *cdev) goto rx_offload_del; } - devm_can_led_init(cdev->net); - of_can_transceiver(cdev->net); dev_info(cdev->dev, "%s device registered (irq=%d, version=%d)\n", diff --git a/drivers/net/can/m_can/m_can.h b/drivers/net/can/m_can/m_can.h index d18b515e6ccc..4c0267f9f297 100644 --- a/drivers/net/can/m_can/m_can.h +++ b/drivers/net/can/m_can/m_can.h @@ -7,7 +7,6 @@ #define _CAN_M_CAN_H_ #include <linux/can/core.h> -#include <linux/can/led.h> #include <linux/can/rx-offload.h> #include <linux/completion.h> #include <linux/device.h> diff --git a/drivers/net/can/mscan/mpc5xxx_can.c b/drivers/net/can/mscan/mpc5xxx_can.c index de4ddf79ba9b..65ba6697bd7d 100644 --- a/drivers/net/can/mscan/mpc5xxx_can.c +++ b/drivers/net/can/mscan/mpc5xxx_can.c @@ -14,6 +14,8 @@ #include <linux/platform_device.h> #include <linux/netdevice.h> #include <linux/can/dev.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> #include <linux/of_platform.h> #include <sysdev/fsl_soc.h> #include <linux/clk.h> diff --git a/drivers/net/can/mscan/mscan.c b/drivers/net/can/mscan/mscan.c index 5b5802fac772..78a21ab63601 100644 --- a/drivers/net/can/mscan/mscan.c +++ b/drivers/net/can/mscan/mscan.c @@ -679,7 +679,7 @@ struct net_device *alloc_mscandev(void) dev->flags |= IFF_ECHO; /* we support local echo */ - netif_napi_add(dev, &priv->napi, mscan_rx_poll, 8); + netif_napi_add_weight(dev, &priv->napi, mscan_rx_poll, 8); priv->can.bittiming_const = &mscan_bittiming_const; priv->can.do_set_bittiming = mscan_do_set_bittiming; diff --git a/drivers/net/can/pch_can.c b/drivers/net/can/pch_can.c index 888bef03de09..fde3ac516d26 100644 --- a/drivers/net/can/pch_can.c +++ b/drivers/net/can/pch_can.c @@ -1189,7 +1189,7 @@ static int pch_can_probe(struct pci_dev *pdev, ndev->netdev_ops = &pch_can_netdev_ops; priv->can.clock.freq = PCH_CAN_CLK; /* Hz */ - netif_napi_add(ndev, &priv->napi, pch_can_poll, PCH_RX_OBJ_END); + netif_napi_add_weight(ndev, &priv->napi, pch_can_poll, PCH_RX_OBJ_END); rc = pci_enable_msi(priv->dev); if (rc) { diff --git a/drivers/net/can/rcar/rcar_can.c b/drivers/net/can/rcar/rcar_can.c index 33e37395379d..d45762f1cf6b 100644 --- a/drivers/net/can/rcar/rcar_can.c +++ b/drivers/net/can/rcar/rcar_can.c @@ -12,7 +12,6 @@ #include <linux/errno.h> #include <linux/netdevice.h> #include <linux/platform_device.h> -#include <linux/can/led.h> #include <linux/can/dev.h> #include <linux/clk.h> #include <linux/of.h> @@ -389,7 +388,6 @@ static void rcar_can_tx_done(struct net_device *ndev) /* Clear interrupt */ isr = readb(&priv->regs->isr); writeb(isr & ~RCAR_CAN_ISR_TXFF, &priv->regs->isr); - can_led_event(ndev, CAN_LED_EVENT_TX); } static irqreturn_t rcar_can_interrupt(int irq, void *dev_id) @@ -531,7 +529,6 @@ static int rcar_can_open(struct net_device *ndev) ndev->irq, err); goto out_close; } - can_led_event(ndev, CAN_LED_EVENT_OPEN); rcar_can_start(ndev); netif_start_queue(ndev); return 0; @@ -581,7 +578,6 @@ static int rcar_can_close(struct net_device *ndev) clk_disable_unprepare(priv->can_clk); clk_disable_unprepare(priv->clk); close_candev(ndev); - can_led_event(ndev, CAN_LED_EVENT_STOP); return 0; } @@ -666,8 +662,6 @@ static void rcar_can_rx_pkt(struct rcar_can_priv *priv) } stats->rx_packets++; - can_led_event(priv->ndev, CAN_LED_EVENT_RX); - netif_receive_skb(skb); } @@ -803,8 +797,8 @@ static int rcar_can_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ndev); SET_NETDEV_DEV(ndev, &pdev->dev); - netif_napi_add(ndev, &priv->napi, rcar_can_rx_poll, - RCAR_CAN_NAPI_WEIGHT); + netif_napi_add_weight(ndev, &priv->napi, rcar_can_rx_poll, + RCAR_CAN_NAPI_WEIGHT); err = register_candev(ndev); if (err) { dev_err(&pdev->dev, "register_candev() failed, error %d\n", @@ -812,8 +806,6 @@ static int rcar_can_probe(struct platform_device *pdev) goto fail_candev; } - devm_can_led_init(ndev); - dev_info(&pdev->dev, "device registered (IRQ%d)\n", ndev->irq); return 0; diff --git a/drivers/net/can/rcar/rcar_canfd.c b/drivers/net/can/rcar/rcar_canfd.c index 1e121e04208c..40a11445d021 100644 --- a/drivers/net/can/rcar/rcar_canfd.c +++ b/drivers/net/can/rcar/rcar_canfd.c @@ -29,7 +29,6 @@ #include <linux/errno.h> #include <linux/netdevice.h> #include <linux/platform_device.h> -#include <linux/can/led.h> #include <linux/can/dev.h> #include <linux/clk.h> #include <linux/of.h> @@ -1128,7 +1127,6 @@ static void rcar_canfd_tx_done(struct net_device *ndev) /* Clear interrupt */ rcar_canfd_write(priv->base, RCANFD_CFSTS(gpriv, ch, RCANFD_CFFIFO_IDX), sts & ~RCANFD_CFSTS_CFTXIF); - can_led_event(ndev, CAN_LED_EVENT_TX); } static void rcar_canfd_handle_global_err(struct rcar_canfd_global *gpriv, u32 ch) @@ -1419,7 +1417,6 @@ static int rcar_canfd_open(struct net_device *ndev) if (err) goto out_close; netif_start_queue(ndev); - can_led_event(ndev, CAN_LED_EVENT_OPEN); return 0; out_close: napi_disable(&priv->napi); @@ -1469,7 +1466,6 @@ static int rcar_canfd_close(struct net_device *ndev) napi_disable(&priv->napi); clk_disable_unprepare(gpriv->can_clk); close_candev(ndev); - can_led_event(ndev, CAN_LED_EVENT_STOP); return 0; } @@ -1619,8 +1615,6 @@ static void rcar_canfd_rx_pkt(struct rcar_canfd_channel *priv) */ rcar_canfd_write(priv->base, RCANFD_RFPCTR(gpriv, ridx), 0xff); - can_led_event(priv->ndev, CAN_LED_EVENT_RX); - if (!(cf->can_id & CAN_RTR_FLAG)) stats->rx_bytes += cf->len; stats->rx_packets++; @@ -1789,10 +1783,9 @@ static int rcar_canfd_channel_probe(struct rcar_canfd_global *gpriv, u32 ch, priv->gpriv = gpriv; SET_NETDEV_DEV(ndev, &pdev->dev); - netif_napi_add(ndev, &priv->napi, rcar_canfd_rx_poll, - RCANFD_NAPI_WEIGHT); + netif_napi_add_weight(ndev, &priv->napi, rcar_canfd_rx_poll, + RCANFD_NAPI_WEIGHT); spin_lock_init(&priv->tx_lock); - devm_can_led_init(ndev); gpriv->ch[priv->channel] = priv; err = register_candev(ndev); if (err) { diff --git a/drivers/net/can/sja1000/Kconfig b/drivers/net/can/sja1000/Kconfig index 110071b26921..4b2f9cb17fc3 100644 --- a/drivers/net/can/sja1000/Kconfig +++ b/drivers/net/can/sja1000/Kconfig @@ -107,7 +107,7 @@ config CAN_TSCAN1 depends on ISA help This driver is for Technologic Systems' TSCAN-1 PC104 boards. - http://www.embeddedarm.com/products/board-detail.php?product=TS-CAN1 + https://www.embeddedts.com/products/TS-CAN1 The driver supports multiple boards and automatically configures them: PLD IO base addresses are read from jumpers JP1 and JP2, IRQ numbers are read from jumpers JP4 and JP5, diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c index 966316479485..2e7638f98cf1 100644 --- a/drivers/net/can/sja1000/sja1000.c +++ b/drivers/net/can/sja1000/sja1000.c @@ -60,7 +60,6 @@ #include <linux/can/dev.h> #include <linux/can/error.h> -#include <linux/can/led.h> #include "sja1000.h" @@ -383,8 +382,6 @@ static void sja1000_rx(struct net_device *dev) sja1000_write_cmdreg(priv, CMD_RRB); netif_rx(skb); - - can_led_event(dev, CAN_LED_EVENT_RX); } static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status) @@ -531,7 +528,6 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id) stats->tx_packets++; } netif_wake_queue(dev); - can_led_event(dev, CAN_LED_EVENT_TX); } if (isrc & IRQ_RI) { /* receive interrupt */ @@ -587,8 +583,6 @@ static int sja1000_open(struct net_device *dev) /* init and start chi */ sja1000_start(dev); - can_led_event(dev, CAN_LED_EVENT_OPEN); - netif_start_queue(dev); return 0; @@ -606,8 +600,6 @@ static int sja1000_close(struct net_device *dev) close_candev(dev); - can_led_event(dev, CAN_LED_EVENT_STOP); - return 0; } @@ -673,9 +665,6 @@ int register_sja1000dev(struct net_device *dev) ret = register_candev(dev); - if (!ret) - devm_can_led_init(dev); - return ret; } EXPORT_SYMBOL_GPL(register_sja1000dev); diff --git a/drivers/net/can/sja1000/tscan1.c b/drivers/net/can/sja1000/tscan1.c index 3dbba8d61afb..f3862bed3d40 100644 --- a/drivers/net/can/sja1000/tscan1.c +++ b/drivers/net/can/sja1000/tscan1.c @@ -5,10 +5,9 @@ * Copyright 2010 Andre B. Oliveira */ -/* - * References: - * - Getting started with TS-CAN1, Technologic Systems, Jun 2009 - * http://www.embeddedarm.com/documentation/ts-can1-manual.pdf +/* References: + * - Getting started with TS-CAN1, Technologic Systems, Feb 2022 + * https://docs.embeddedts.com/TS-CAN1 */ #include <linux/init.h> diff --git a/drivers/net/can/slcan.c b/drivers/net/can/slcan.c index ec294d0c5722..64a3aee8a7da 100644 --- a/drivers/net/can/slcan.c +++ b/drivers/net/can/slcan.c @@ -359,8 +359,8 @@ static netdev_tx_t slc_xmit(struct sk_buff *skb, struct net_device *dev) { struct slcan *sl = netdev_priv(dev); - if (skb->len != CAN_MTU) - goto out; + if (can_dropped_invalid_skb(dev, skb)) + return NETDEV_TX_OK; spin_lock(&sl->lock); if (!netif_running(dev)) { diff --git a/drivers/net/can/spi/hi311x.c b/drivers/net/can/spi/hi311x.c index a5b2952b8d0f..ebc4ebb44c98 100644 --- a/drivers/net/can/spi/hi311x.c +++ b/drivers/net/can/spi/hi311x.c @@ -16,7 +16,6 @@ #include <linux/can/core.h> #include <linux/can/dev.h> -#include <linux/can/led.h> #include <linux/clk.h> #include <linux/completion.h> #include <linux/delay.h> @@ -354,8 +353,6 @@ static void hi3110_hw_rx(struct spi_device *spi) } priv->net->stats.rx_packets++; - can_led_event(priv->net, CAN_LED_EVENT_RX); - netif_rx(skb); } @@ -567,8 +564,6 @@ static int hi3110_stop(struct net_device *net) mutex_unlock(&priv->hi3110_lock); - can_led_event(net, CAN_LED_EVENT_STOP); - return 0; } @@ -725,7 +720,6 @@ static irqreturn_t hi3110_can_ist(int irq, void *dev_id) if (priv->tx_busy && statf & HI3110_STAT_TXMTY) { net->stats.tx_packets++; net->stats.tx_bytes += can_get_echo_skb(net, 0, NULL); - can_led_event(net, CAN_LED_EVENT_TX); priv->tx_busy = false; netif_wake_queue(net); } @@ -783,7 +777,6 @@ static int hi3110_open(struct net_device *net) if (ret) goto out_free_wq; - can_led_event(net, CAN_LED_EVENT_OPEN); netif_wake_queue(net); mutex_unlock(&priv->hi3110_lock); @@ -931,7 +924,6 @@ static int hi3110_can_probe(struct spi_device *spi) if (ret) goto error_probe; - devm_can_led_init(net); netdev_info(net, "%x successfully initialized.\n", priv->model); return 0; diff --git a/drivers/net/can/spi/mcp251x.c b/drivers/net/can/spi/mcp251x.c index fc747bff5eeb..666a4505a55a 100644 --- a/drivers/net/can/spi/mcp251x.c +++ b/drivers/net/can/spi/mcp251x.c @@ -22,7 +22,6 @@ #include <linux/bitfield.h> #include <linux/can/core.h> #include <linux/can/dev.h> -#include <linux/can/led.h> #include <linux/clk.h> #include <linux/completion.h> #include <linux/delay.h> @@ -738,8 +737,6 @@ static void mcp251x_hw_rx(struct spi_device *spi, int buf_idx) } priv->net->stats.rx_packets++; - can_led_event(priv->net, CAN_LED_EVENT_RX); - netif_rx(skb); } @@ -973,8 +970,6 @@ static int mcp251x_stop(struct net_device *net) mutex_unlock(&priv->mcp_lock); - can_led_event(net, CAN_LED_EVENT_STOP); - return 0; } @@ -1177,7 +1172,6 @@ static irqreturn_t mcp251x_can_ist(int irq, void *dev_id) break; if (intf & CANINTF_TX) { - can_led_event(net, CAN_LED_EVENT_TX); if (priv->tx_busy) { net->stats.tx_packets++; net->stats.tx_bytes += can_get_echo_skb(net, 0, @@ -1232,8 +1226,6 @@ static int mcp251x_open(struct net_device *net) if (ret) goto out_free_irq; - can_led_event(net, CAN_LED_EVENT_OPEN); - netif_wake_queue(net); mutex_unlock(&priv->mcp_lock); @@ -1403,8 +1395,6 @@ static int mcp251x_can_probe(struct spi_device *spi) if (ret) goto error_probe; - devm_can_led_init(net); - ret = mcp251x_gpio_setup(priv); if (ret) goto error_probe; diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c index f9dd8fdba12b..b21252390216 100644 --- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c +++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c @@ -37,6 +37,12 @@ static const struct mcp251xfd_devtype_data mcp251xfd_devtype_data_mcp2518fd = { .model = MCP251XFD_MODEL_MCP2518FD, }; +static const struct mcp251xfd_devtype_data mcp251xfd_devtype_data_mcp251863 = { + .quirks = MCP251XFD_QUIRK_CRC_REG | MCP251XFD_QUIRK_CRC_RX | + MCP251XFD_QUIRK_CRC_TX | MCP251XFD_QUIRK_ECC, + .model = MCP251XFD_MODEL_MCP251863, +}; + /* Autodetect model, start with CRC enabled. */ static const struct mcp251xfd_devtype_data mcp251xfd_devtype_data_mcp251xfd = { .quirks = MCP251XFD_QUIRK_CRC_REG | MCP251XFD_QUIRK_CRC_RX | @@ -75,6 +81,8 @@ static const char *__mcp251xfd_get_model_str(enum mcp251xfd_model model) return "MCP2517FD"; case MCP251XFD_MODEL_MCP2518FD: return "MCP2518FD"; + case MCP251XFD_MODEL_MCP251863: + return "MCP251863"; case MCP251XFD_MODEL_MCP251XFD: return "MCP251xFD"; } @@ -916,7 +924,7 @@ static int mcp251xfd_handle_rxovif(struct mcp251xfd_priv *priv) cf->can_id |= CAN_ERR_CRTL; cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; - err = can_rx_offload_queue_sorted(&priv->offload, skb, timestamp); + err = can_rx_offload_queue_timestamp(&priv->offload, skb, timestamp); if (err) stats->rx_fifo_errors++; @@ -1021,7 +1029,7 @@ static int mcp251xfd_handle_ivmif(struct mcp251xfd_priv *priv) return 0; mcp251xfd_skb_set_timestamp(priv, skb, timestamp); - err = can_rx_offload_queue_sorted(&priv->offload, skb, timestamp); + err = can_rx_offload_queue_timestamp(&priv->offload, skb, timestamp); if (err) stats->rx_fifo_errors++; @@ -1094,7 +1102,7 @@ static int mcp251xfd_handle_cerrif(struct mcp251xfd_priv *priv) cf->data[7] = bec.rxerr; } - err = can_rx_offload_queue_sorted(&priv->offload, skb, timestamp); + err = can_rx_offload_queue_timestamp(&priv->offload, skb, timestamp); if (err) stats->rx_fifo_errors++; @@ -1259,7 +1267,8 @@ mcp251xfd_handle_eccif_recover(struct mcp251xfd_priv *priv, u8 nr) * - for mcp2518fd: offset not 0 or 1 */ if (chip_tx_tail != tx_tail || - !(offset == 0 || (offset == 1 && mcp251xfd_is_2518(priv)))) { + !(offset == 0 || (offset == 1 && (mcp251xfd_is_2518FD(priv) || + mcp251xfd_is_251863(priv))))) { netdev_err(priv->ndev, "ECC Error information inconsistent (addr=0x%04x, nr=%d, tx_tail=0x%08x(%d), chip_tx_tail=%d, offset=%d).\n", addr, nr, tx_ring->tail, tx_tail, chip_tx_tail, @@ -1697,7 +1706,7 @@ static int mcp251xfd_register_chip_detect(struct mcp251xfd_priv *priv) else devtype_data = &mcp251xfd_devtype_data_mcp2517fd; - if (!mcp251xfd_is_251X(priv) && + if (!mcp251xfd_is_251XFD(priv) && priv->devtype_data.model != devtype_data->model) { netdev_info(ndev, "Detected %s, but firmware specifies a %s. Fixing up.\n", @@ -1930,6 +1939,9 @@ static const struct of_device_id mcp251xfd_of_match[] = { .compatible = "microchip,mcp2518fd", .data = &mcp251xfd_devtype_data_mcp2518fd, }, { + .compatible = "microchip,mcp251863", + .data = &mcp251xfd_devtype_data_mcp251863, + }, { .compatible = "microchip,mcp251xfd", .data = &mcp251xfd_devtype_data_mcp251xfd, }, { @@ -1946,6 +1958,9 @@ static const struct spi_device_id mcp251xfd_id_table[] = { .name = "mcp2518fd", .driver_data = (kernel_ulong_t)&mcp251xfd_devtype_data_mcp2518fd, }, { + .name = "mcp251863", + .driver_data = (kernel_ulong_t)&mcp251xfd_devtype_data_mcp251863, + }, { .name = "mcp251xfd", .driver_data = (kernel_ulong_t)&mcp251xfd_devtype_data_mcp251xfd, }, { diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-rx.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-rx.c index d09f7fbf2ba7..ced8d9c81f8c 100644 --- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-rx.c +++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-rx.c @@ -173,7 +173,7 @@ mcp251xfd_handle_rxif_one(struct mcp251xfd_priv *priv, } mcp251xfd_hw_rx_obj_to_skb(priv, hw_rx_obj, skb); - err = can_rx_offload_queue_sorted(&priv->offload, skb, hw_rx_obj->ts); + err = can_rx_offload_queue_timestamp(&priv->offload, skb, hw_rx_obj->ts); if (err) stats->rx_fifo_errors++; diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd.h b/drivers/net/can/spi/mcp251xfd/mcp251xfd.h index 9cb6b5ad8dda..2b0309fedfac 100644 --- a/drivers/net/can/spi/mcp251xfd/mcp251xfd.h +++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd.h @@ -441,7 +441,7 @@ struct mcp251xfd_hw_tef_obj { /* The tx_obj_raw version is used in spi async, i.e. without * regmap. We have to take care of endianness ourselves. */ -struct mcp251xfd_hw_tx_obj_raw { +struct __packed mcp251xfd_hw_tx_obj_raw { __le32 id; __le32 flags; u8 data[sizeof_field(struct canfd_frame, data)]; @@ -586,7 +586,8 @@ struct mcp251xfd_regs_status { enum mcp251xfd_model { MCP251XFD_MODEL_MCP2517FD = 0x2517, MCP251XFD_MODEL_MCP2518FD = 0x2518, - MCP251XFD_MODEL_MCP251XFD = 0xffff, /* autodetect model */ + MCP251XFD_MODEL_MCP251863 = 0x251863, + MCP251XFD_MODEL_MCP251XFD = 0xffffffff, /* autodetect model */ }; struct mcp251xfd_devtype_data { @@ -659,12 +660,13 @@ struct mcp251xfd_priv { static inline bool \ mcp251xfd_is_##_model(const struct mcp251xfd_priv *priv) \ { \ - return priv->devtype_data.model == MCP251XFD_MODEL_MCP##_model##FD; \ + return priv->devtype_data.model == MCP251XFD_MODEL_MCP##_model; \ } -MCP251XFD_IS(2517); -MCP251XFD_IS(2518); -MCP251XFD_IS(251X); +MCP251XFD_IS(2517FD); +MCP251XFD_IS(2518FD); +MCP251XFD_IS(251863); +MCP251XFD_IS(251XFD); static inline bool mcp251xfd_is_fd_mode(const struct mcp251xfd_priv *priv) { diff --git a/drivers/net/can/sun4i_can.c b/drivers/net/can/sun4i_can.c index 25d6d81ab4f4..155b90f6c767 100644 --- a/drivers/net/can/sun4i_can.c +++ b/drivers/net/can/sun4i_can.c @@ -51,7 +51,6 @@ #include <linux/can.h> #include <linux/can/dev.h> #include <linux/can/error.h> -#include <linux/can/led.h> #include <linux/clk.h> #include <linux/delay.h> #include <linux/interrupt.h> @@ -516,8 +515,6 @@ static void sun4i_can_rx(struct net_device *dev) sun4i_can_write_cmdreg(priv, SUN4I_CMD_RELEASE_RBUF); netif_rx(skb); - - can_led_event(dev, CAN_LED_EVENT_RX); } static int sun4i_can_err(struct net_device *dev, u8 isrc, u8 status) @@ -664,7 +661,6 @@ static irqreturn_t sun4i_can_interrupt(int irq, void *dev_id) stats->tx_bytes += can_get_echo_skb(dev, 0, NULL); stats->tx_packets++; netif_wake_queue(dev); - can_led_event(dev, CAN_LED_EVENT_TX); } if ((isrc & SUN4I_INT_RBUF_VLD) && !(isrc & SUN4I_INT_DATA_OR)) { @@ -729,7 +725,6 @@ static int sun4ican_open(struct net_device *dev) goto exit_can_start; } - can_led_event(dev, CAN_LED_EVENT_OPEN); netif_start_queue(dev); return 0; @@ -756,7 +751,6 @@ static int sun4ican_close(struct net_device *dev) free_irq(dev->irq, dev); close_candev(dev); - can_led_event(dev, CAN_LED_EVENT_STOP); return 0; } @@ -883,7 +877,6 @@ static int sun4ican_probe(struct platform_device *pdev) DRV_NAME, err); goto exit_free; } - devm_can_led_init(dev); dev_info(&pdev->dev, "device registered (base=%p, irq=%d)\n", priv->base, dev->irq); diff --git a/drivers/net/can/ti_hecc.c b/drivers/net/can/ti_hecc.c index ff31b993ab17..debe17bfd0f0 100644 --- a/drivers/net/can/ti_hecc.c +++ b/drivers/net/can/ti_hecc.c @@ -34,7 +34,6 @@ #include <linux/can/dev.h> #include <linux/can/error.h> -#include <linux/can/led.h> #include <linux/can/rx-offload.h> #define DRV_NAME "ti_hecc" @@ -633,7 +632,7 @@ static int ti_hecc_error(struct net_device *ndev, int int_status, cf->data[3] = CAN_ERR_PROT_LOC_ACK; timestamp = hecc_read(priv, HECC_CANLNT); - err = can_rx_offload_queue_sorted(&priv->offload, skb, + err = can_rx_offload_queue_timestamp(&priv->offload, skb, timestamp); if (err) ndev->stats.rx_fifo_errors++; @@ -668,7 +667,7 @@ static void ti_hecc_change_state(struct net_device *ndev, } timestamp = hecc_read(priv, HECC_CANLNT); - err = can_rx_offload_queue_sorted(&priv->offload, skb, timestamp); + err = can_rx_offload_queue_timestamp(&priv->offload, skb, timestamp); if (err) ndev->stats.rx_fifo_errors++; } @@ -759,7 +758,6 @@ static irqreturn_t ti_hecc_interrupt(int irq, void *dev_id) can_rx_offload_get_echo_skb(&priv->offload, mbxno, stamp, NULL); stats->tx_packets++; - can_led_event(ndev, CAN_LED_EVENT_TX); --priv->tx_tail; } @@ -814,8 +812,6 @@ static int ti_hecc_open(struct net_device *ndev) return err; } - can_led_event(ndev, CAN_LED_EVENT_OPEN); - ti_hecc_start(ndev); can_rx_offload_enable(&priv->offload); netif_start_queue(ndev); @@ -834,8 +830,6 @@ static int ti_hecc_close(struct net_device *ndev) close_candev(ndev); ti_hecc_transceiver_switch(priv, 0); - can_led_event(ndev, CAN_LED_EVENT_STOP); - return 0; } @@ -954,8 +948,6 @@ static int ti_hecc_probe(struct platform_device *pdev) goto probe_exit_offload; } - devm_can_led_init(ndev); - dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%u)\n", priv->base, (u32)ndev->irq); diff --git a/drivers/net/can/usb/kvaser_usb/Makefile b/drivers/net/can/usb/kvaser_usb/Makefile index cf260044f0b9..b20d951a0790 100644 --- a/drivers/net/can/usb/kvaser_usb/Makefile +++ b/drivers/net/can/usb/kvaser_usb/Makefile @@ -1,3 +1,8 @@ # SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_CAN_KVASER_USB) += kvaser_usb.o kvaser_usb-y = kvaser_usb_core.o kvaser_usb_leaf.o kvaser_usb_hydra.o + +# FIXME: temporarily silence -Warray-bounds on non W=1+ builds +ifndef KBUILD_EXTRA_WARN +CFLAGS_kvaser_usb_hydra.o += -Wno-array-bounds +endif diff --git a/drivers/net/can/usb/mcba_usb.c b/drivers/net/can/usb/mcba_usb.c index c45a814e1de2..792ab9da317d 100644 --- a/drivers/net/can/usb/mcba_usb.c +++ b/drivers/net/can/usb/mcba_usb.c @@ -10,7 +10,6 @@ #include <linux/can.h> #include <linux/can/dev.h> #include <linux/can/error.h> -#include <linux/can/led.h> #include <linux/module.h> #include <linux/netdevice.h> #include <linux/signal.h> @@ -232,8 +231,6 @@ static void mcba_usb_write_bulk_callback(struct urb *urb) netdev->stats.tx_packets++; netdev->stats.tx_bytes += can_get_echo_skb(netdev, ctx->ndx, NULL); - - can_led_event(netdev, CAN_LED_EVENT_TX); } if (urb->status) @@ -452,7 +449,6 @@ static void mcba_usb_process_can(struct mcba_priv *priv, } stats->rx_packets++; - can_led_event(priv->netdev, CAN_LED_EVENT_RX); netif_rx(skb); } @@ -700,7 +696,6 @@ static int mcba_usb_open(struct net_device *netdev) priv->can_speed_check = true; priv->can.state = CAN_STATE_ERROR_ACTIVE; - can_led_event(netdev, CAN_LED_EVENT_OPEN); netif_start_queue(netdev); return 0; @@ -732,7 +727,6 @@ static int mcba_usb_close(struct net_device *netdev) mcba_urb_unlink(priv); close_candev(netdev); - can_led_event(netdev, CAN_LED_EVENT_STOP); return 0; } @@ -857,8 +851,6 @@ static int mcba_usb_probe(struct usb_interface *intf, priv->rx_pipe = usb_rcvbulkpipe(priv->udev, in->bEndpointAddress); priv->tx_pipe = usb_sndbulkpipe(priv->udev, out->bEndpointAddress); - devm_can_led_init(netdev); - /* Start USB dev only if we have successfully registered CAN device */ err = mcba_usb_start(priv); if (err) { diff --git a/drivers/net/can/usb/peak_usb/pcan_usb.c b/drivers/net/can/usb/peak_usb/pcan_usb.c index 17dc178f555b..091c631ebe23 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb.c @@ -533,7 +533,7 @@ static int pcan_usb_handle_bus_evt(struct pcan_usb_msg_context *mc, u8 ir) { struct pcan_usb *pdev = mc->pdev; - /* acccording to the content of the packet */ + /* according to the content of the packet */ switch (ir) { case PCAN_USB_ERR_CNT_DEC: case PCAN_USB_ERR_CNT_INC: diff --git a/drivers/net/can/usb/usb_8dev.c b/drivers/net/can/usb/usb_8dev.c index b638604bf1ee..f3363575bf32 100644 --- a/drivers/net/can/usb/usb_8dev.c +++ b/drivers/net/can/usb/usb_8dev.c @@ -21,7 +21,6 @@ #include <linux/can.h> #include <linux/can/dev.h> #include <linux/can/error.h> -#include <linux/can/led.h> /* driver constants */ #define MAX_RX_URBS 20 @@ -480,8 +479,6 @@ static void usb_8dev_rx_can_msg(struct usb_8dev_priv *priv, stats->rx_packets++; netif_rx(skb); - - can_led_event(priv->netdev, CAN_LED_EVENT_RX); } else { netdev_warn(priv->netdev, "frame type %d unknown", msg->type); @@ -582,8 +579,6 @@ static void usb_8dev_write_bulk_callback(struct urb *urb) netdev->stats.tx_packets++; netdev->stats.tx_bytes += can_get_echo_skb(netdev, context->echo_index, NULL); - can_led_event(netdev, CAN_LED_EVENT_TX); - /* Release context */ context->echo_index = MAX_TX_URBS; @@ -807,8 +802,6 @@ static int usb_8dev_open(struct net_device *netdev) if (err) return err; - can_led_event(netdev, CAN_LED_EVENT_OPEN); - /* finally start device */ err = usb_8dev_start(priv); if (err) { @@ -865,8 +858,6 @@ static int usb_8dev_close(struct net_device *netdev) close_candev(netdev); - can_led_event(netdev, CAN_LED_EVENT_STOP); - return err; } @@ -974,8 +965,6 @@ static int usb_8dev_probe(struct usb_interface *intf, (version>>8) & 0xff, version & 0xff); } - devm_can_led_init(netdev); - return 0; cleanup_unregister_candev: diff --git a/drivers/net/can/xilinx_can.c b/drivers/net/can/xilinx_can.c index e562c5ab1149..8a3b7b103ca4 100644 --- a/drivers/net/can/xilinx_can.c +++ b/drivers/net/can/xilinx_can.c @@ -26,7 +26,6 @@ #include <linux/types.h> #include <linux/can/dev.h> #include <linux/can/error.h> -#include <linux/can/led.h> #include <linux/pm_runtime.h> #define DRIVER_NAME "xilinx_can" @@ -239,7 +238,7 @@ static const struct can_bittiming_const xcan_bittiming_const_canfd = { }; /* AXI CANFD Data Bittiming constants as per AXI CANFD 1.0 specs */ -static struct can_bittiming_const xcan_data_bittiming_const_canfd = { +static const struct can_bittiming_const xcan_data_bittiming_const_canfd = { .name = DRIVER_NAME, .tseg1_min = 1, .tseg1_max = 16, @@ -265,7 +264,7 @@ static const struct can_bittiming_const xcan_bittiming_const_canfd2 = { }; /* AXI CANFD 2.0 Data Bittiming constants as per AXI CANFD 2.0 spec */ -static struct can_bittiming_const xcan_data_bittiming_const_canfd2 = { +static const struct can_bittiming_const xcan_data_bittiming_const_canfd2 = { .name = DRIVER_NAME, .tseg1_min = 1, .tseg1_max = 32, @@ -1209,10 +1208,8 @@ static int xcan_rx_poll(struct napi_struct *napi, int quota) XCAN_IXR_RXNEMP_MASK); } - if (work_done) { - can_led_event(ndev, CAN_LED_EVENT_RX); + if (work_done) xcan_update_error_state_after_rxtx(ndev); - } if (work_done < quota) { if (napi_complete_done(napi, work_done)) { @@ -1298,7 +1295,6 @@ static void xcan_tx_interrupt(struct net_device *ndev, u32 isr) spin_unlock_irqrestore(&priv->tx_lock, flags); - can_led_event(ndev, CAN_LED_EVENT_TX); xcan_update_error_state_after_rxtx(ndev); } @@ -1420,7 +1416,6 @@ static int xcan_open(struct net_device *ndev) goto err_candev; } - can_led_event(ndev, CAN_LED_EVENT_OPEN); napi_enable(&priv->napi); netif_start_queue(ndev); @@ -1452,7 +1447,6 @@ static int xcan_close(struct net_device *ndev) free_irq(ndev->irq, ndev); close_candev(ndev); - can_led_event(ndev, CAN_LED_EVENT_STOP); pm_runtime_put(priv->dev); return 0; @@ -1804,7 +1798,7 @@ static int xcan_probe(struct platform_device *pdev) priv->can.clock.freq = clk_get_rate(priv->can_clk); - netif_napi_add(ndev, &priv->napi, xcan_rx_poll, rx_max); + netif_napi_add_weight(ndev, &priv->napi, xcan_rx_poll, rx_max); ret = register_candev(ndev); if (ret) { @@ -1812,8 +1806,6 @@ static int xcan_probe(struct platform_device *pdev) goto err_disableclks; } - devm_can_led_init(ndev); - pm_runtime_put(&pdev->dev); if (priv->devtype.flags & XCAN_FLAG_CANFD_2) { |