diff options
Diffstat (limited to 'drivers/net/can')
28 files changed, 799 insertions, 338 deletions
diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig index cf989bea9aa3..d43d56694667 100644 --- a/drivers/net/can/Kconfig +++ b/drivers/net/can/Kconfig @@ -154,6 +154,7 @@ config CAN_JANZ_ICAN3 config CAN_KVASER_PCIEFD depends on PCI tristate "Kvaser PCIe FD cards" + select NET_DEVLINK help This is a driver for the Kvaser PCI Express CAN FD family. @@ -201,7 +202,7 @@ config CAN_SUN4I be called sun4i_can. config CAN_TI_HECC - depends on ARM + depends on ARM || COMPILE_TEST tristate "TI High End CAN Controller" select CAN_RX_OFFLOAD help diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile index a71db2cfe990..56138d8ddfd2 100644 --- a/drivers/net/can/Makefile +++ b/drivers/net/can/Makefile @@ -25,7 +25,7 @@ obj-$(CONFIG_CAN_FLEXCAN) += flexcan/ obj-$(CONFIG_CAN_GRCAN) += grcan.o obj-$(CONFIG_CAN_IFI_CANFD) += ifi_canfd/ obj-$(CONFIG_CAN_JANZ_ICAN3) += janz-ican3.o -obj-$(CONFIG_CAN_KVASER_PCIEFD) += kvaser_pciefd.o +obj-$(CONFIG_CAN_KVASER_PCIEFD) += kvaser_pciefd/ obj-$(CONFIG_CAN_MSCAN) += mscan/ obj-$(CONFIG_CAN_M_CAN) += m_can/ obj-$(CONFIG_CAN_PEAK_PCIEFD) += peak_canfd/ diff --git a/drivers/net/can/ctucanfd/ctucanfd_base.c b/drivers/net/can/ctucanfd/ctucanfd_base.c index bf6398772960..8bd3f0fc385c 100644 --- a/drivers/net/can/ctucanfd/ctucanfd_base.c +++ b/drivers/net/can/ctucanfd/ctucanfd_base.c @@ -506,11 +506,12 @@ static bool ctucan_is_txt_buf_writable(struct ctucan_priv *priv, u8 buf) * @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 + * 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) diff --git a/drivers/net/can/dev/calc_bittiming.c b/drivers/net/can/dev/calc_bittiming.c index 3809c148fb88..a94bd67c670c 100644 --- a/drivers/net/can/dev/calc_bittiming.c +++ b/drivers/net/can/dev/calc_bittiming.c @@ -179,7 +179,7 @@ void can_calc_tdco(struct can_tdc *tdc, const struct can_tdc_const *tdc_const, if (!tdc_const || !(ctrlmode_supported & CAN_CTRLMODE_TDC_AUTO)) return; - *ctrlmode &= ~CAN_CTRLMODE_TDC_MASK; + *ctrlmode &= ~CAN_CTRLMODE_FD_TDC_MASK; /* As specified in ISO 11898-1 section 11.3.3 "Transmitter * delay compensation" (TDC) is only applicable if data BRP is diff --git a/drivers/net/can/dev/netlink.c b/drivers/net/can/dev/netlink.c index f0e3f0d538fb..d9f6ab3efb97 100644 --- a/drivers/net/can/dev/netlink.c +++ b/drivers/net/can/dev/netlink.c @@ -18,7 +18,7 @@ static const struct nla_policy can_policy[IFLA_CAN_MAX + 1] = { [IFLA_CAN_CLOCK] = { .len = sizeof(struct can_clock) }, [IFLA_CAN_BERR_COUNTER] = { .len = sizeof(struct can_berr_counter) }, [IFLA_CAN_DATA_BITTIMING] = { .len = sizeof(struct can_bittiming) }, - [IFLA_CAN_DATA_BITTIMING_CONST] = { .len = sizeof(struct can_bittiming_const) }, + [IFLA_CAN_DATA_BITTIMING_CONST] = { .len = sizeof(struct can_bittiming_const) }, [IFLA_CAN_TERMINATION] = { .type = NLA_U16 }, [IFLA_CAN_TDC] = { .type = NLA_NESTED }, [IFLA_CAN_CTRLMODE_EXT] = { .type = NLA_NESTED }, @@ -67,12 +67,12 @@ static int can_validate(struct nlattr *tb[], struct nlattr *data[], if (data[IFLA_CAN_CTRLMODE]) { struct can_ctrlmode *cm = nla_data(data[IFLA_CAN_CTRLMODE]); - u32 tdc_flags = cm->flags & CAN_CTRLMODE_TDC_MASK; + u32 tdc_flags = cm->flags & CAN_CTRLMODE_FD_TDC_MASK; is_can_fd = cm->flags & cm->mask & CAN_CTRLMODE_FD; /* CAN_CTRLMODE_TDC_{AUTO,MANUAL} are mutually exclusive */ - if (tdc_flags == CAN_CTRLMODE_TDC_MASK) + if (tdc_flags == CAN_CTRLMODE_FD_TDC_MASK) return -EOPNOTSUPP; /* If one of the CAN_CTRLMODE_TDC_* flag is set then * TDC must be set and vice-versa @@ -144,7 +144,7 @@ static int can_tdc_changelink(struct can_priv *priv, const struct nlattr *nla, const struct can_tdc_const *tdc_const = priv->fd.tdc_const; int err; - if (!tdc_const || !can_tdc_is_enabled(priv)) + if (!tdc_const || !can_fd_tdc_is_enabled(priv)) return -EOPNOTSUPP; err = nla_parse_nested(tb_tdc, IFLA_CAN_TDC_MAX, nla, @@ -189,7 +189,7 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[], struct netlink_ext_ack *extack) { struct can_priv *priv = netdev_priv(dev); - u32 tdc_mask = 0; + bool fd_tdc_flag_provided = false; int err; /* We need synchronization with dev->stop() */ @@ -230,16 +230,16 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[], dev->mtu = CAN_MTU; memset(&priv->fd.data_bittiming, 0, sizeof(priv->fd.data_bittiming)); - priv->ctrlmode &= ~CAN_CTRLMODE_TDC_MASK; + priv->ctrlmode &= ~CAN_CTRLMODE_FD_TDC_MASK; memset(&priv->fd.tdc, 0, sizeof(priv->fd.tdc)); } - tdc_mask = cm->mask & CAN_CTRLMODE_TDC_MASK; + fd_tdc_flag_provided = cm->mask & CAN_CTRLMODE_FD_TDC_MASK; /* CAN_CTRLMODE_TDC_{AUTO,MANUAL} are mutually * exclusive: make sure to turn the other one off */ - if (tdc_mask) - priv->ctrlmode &= cm->flags | ~CAN_CTRLMODE_TDC_MASK; + if (fd_tdc_flag_provided) + priv->ctrlmode &= cm->flags | ~CAN_CTRLMODE_FD_TDC_MASK; } if (data[IFLA_CAN_BITTIMING]) { @@ -351,10 +351,10 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[], err = can_tdc_changelink(priv, data[IFLA_CAN_TDC], extack); if (err) { - priv->ctrlmode &= ~CAN_CTRLMODE_TDC_MASK; + priv->ctrlmode &= ~CAN_CTRLMODE_FD_TDC_MASK; return err; } - } else if (!tdc_mask) { + } else if (!fd_tdc_flag_provided) { /* Neither of TDC parameters nor TDC flags are * provided: do calculation */ @@ -421,7 +421,7 @@ static size_t can_tdc_get_size(const struct net_device *dev) size += nla_total_size(sizeof(u32)); /* IFLA_CAN_TDCF_MAX */ } - if (can_tdc_is_enabled(priv)) { + if (can_fd_tdc_is_enabled(priv)) { if (priv->ctrlmode & CAN_CTRLMODE_TDC_MANUAL || priv->fd.do_get_auto_tdcv) size += nla_total_size(sizeof(u32)); /* IFLA_CAN_TDCV */ @@ -502,7 +502,7 @@ static int can_tdc_fill_info(struct sk_buff *skb, const struct net_device *dev) nla_put_u32(skb, IFLA_CAN_TDC_TDCF_MAX, tdc_const->tdcf_max))) goto err_cancel; - if (can_tdc_is_enabled(priv)) { + if (can_fd_tdc_is_enabled(priv)) { u32 tdcv; int err = -EINVAL; diff --git a/drivers/net/can/janz-ican3.c b/drivers/net/can/janz-ican3.c index 60c7b83b4539..bfa5cbe88017 100644 --- a/drivers/net/can/janz-ican3.c +++ b/drivers/net/can/janz-ican3.c @@ -1867,7 +1867,7 @@ static ssize_t fwinfo_show(struct device *dev, { struct ican3_dev *mod = netdev_priv(to_net_dev(dev)); - return scnprintf(buf, PAGE_SIZE, "%s\n", mod->fwinfo); + return sysfs_emit(buf, "%s\n", mod->fwinfo); } static DEVICE_ATTR_RW(termination); diff --git a/drivers/net/can/kvaser_pciefd/Makefile b/drivers/net/can/kvaser_pciefd/Makefile new file mode 100644 index 000000000000..8c5b8cdc6b5f --- /dev/null +++ b/drivers/net/can/kvaser_pciefd/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_CAN_KVASER_PCIEFD) += kvaser_pciefd.o +kvaser_pciefd-y = kvaser_pciefd_core.o kvaser_pciefd_devlink.o diff --git a/drivers/net/can/kvaser_pciefd/kvaser_pciefd.h b/drivers/net/can/kvaser_pciefd/kvaser_pciefd.h new file mode 100644 index 000000000000..08c9ddc1ee85 --- /dev/null +++ b/drivers/net/can/kvaser_pciefd/kvaser_pciefd.h @@ -0,0 +1,96 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ +/* kvaser_pciefd common definitions and declarations + * + * Copyright (C) 2025 KVASER AB, Sweden. All rights reserved. + */ + +#ifndef _KVASER_PCIEFD_H +#define _KVASER_PCIEFD_H + +#include <linux/can/dev.h> +#include <linux/completion.h> +#include <linux/pci.h> +#include <linux/spinlock.h> +#include <linux/timer.h> +#include <linux/types.h> +#include <net/devlink.h> + +#define KVASER_PCIEFD_MAX_CAN_CHANNELS 8UL +#define KVASER_PCIEFD_DMA_COUNT 2U +#define KVASER_PCIEFD_DMA_SIZE (4U * 1024U) +#define KVASER_PCIEFD_CAN_TX_MAX_COUNT 17U + +struct kvaser_pciefd; + +struct kvaser_pciefd_address_offset { + u32 serdes; + u32 pci_ien; + u32 pci_irq; + u32 sysid; + u32 loopback; + u32 kcan_srb_fifo; + u32 kcan_srb; + u32 kcan_ch0; + u32 kcan_ch1; +}; + +struct kvaser_pciefd_irq_mask { + u32 kcan_rx0; + u32 kcan_tx[KVASER_PCIEFD_MAX_CAN_CHANNELS]; + u32 all; +}; + +struct kvaser_pciefd_dev_ops { + void (*kvaser_pciefd_write_dma_map)(struct kvaser_pciefd *pcie, + dma_addr_t addr, int index); +}; + +struct kvaser_pciefd_driver_data { + const struct kvaser_pciefd_address_offset *address_offset; + const struct kvaser_pciefd_irq_mask *irq_mask; + const struct kvaser_pciefd_dev_ops *ops; +}; + +struct kvaser_pciefd_fw_version { + u8 major; + u8 minor; + u16 build; +}; + +struct kvaser_pciefd_can { + struct can_priv can; + struct devlink_port devlink_port; + struct kvaser_pciefd *kv_pcie; + void __iomem *reg_base; + struct can_berr_counter bec; + u32 ioc; + u8 cmd_seq; + u8 tx_max_count; + u8 tx_idx; + u8 ack_idx; + int err_rep_cnt; + unsigned int completed_tx_pkts; + unsigned int completed_tx_bytes; + spinlock_t lock; /* Locks sensitive registers (e.g. MODE) */ + struct timer_list bec_poll_timer; + struct completion start_comp, flush_comp; +}; + +struct kvaser_pciefd { + struct pci_dev *pci; + void __iomem *reg_base; + struct kvaser_pciefd_can *can[KVASER_PCIEFD_MAX_CAN_CHANNELS]; + const struct kvaser_pciefd_driver_data *driver_data; + void *dma_data[KVASER_PCIEFD_DMA_COUNT]; + u8 nr_channels; + u32 bus_freq; + u32 freq; + u32 freq_to_ticks_div; + struct kvaser_pciefd_fw_version fw_version; +}; + +extern const struct devlink_ops kvaser_pciefd_devlink_ops; + +int kvaser_pciefd_devlink_port_register(struct kvaser_pciefd_can *can); +void kvaser_pciefd_devlink_port_unregister(struct kvaser_pciefd_can *can); +#endif /* _KVASER_PCIEFD_H */ diff --git a/drivers/net/can/kvaser_pciefd.c b/drivers/net/can/kvaser_pciefd/kvaser_pciefd_core.c index 09510663988c..0880023611be 100644 --- a/drivers/net/can/kvaser_pciefd.c +++ b/drivers/net/can/kvaser_pciefd/kvaser_pciefd_core.c @@ -5,6 +5,8 @@ * - PEAK linux canfd driver */ +#include "kvaser_pciefd.h" + #include <linux/bitfield.h> #include <linux/can/dev.h> #include <linux/device.h> @@ -27,10 +29,6 @@ MODULE_DESCRIPTION("CAN driver for Kvaser CAN/PCIe devices"); #define KVASER_PCIEFD_WAIT_TIMEOUT msecs_to_jiffies(1000) #define KVASER_PCIEFD_BEC_POLL_FREQ (jiffies + msecs_to_jiffies(200)) #define KVASER_PCIEFD_MAX_ERR_REP 256U -#define KVASER_PCIEFD_CAN_TX_MAX_COUNT 17U -#define KVASER_PCIEFD_MAX_CAN_CHANNELS 8UL -#define KVASER_PCIEFD_DMA_COUNT 2U -#define KVASER_PCIEFD_DMA_SIZE (4U * 1024U) #define KVASER_PCIEFD_VENDOR 0x1a07 @@ -66,6 +64,7 @@ MODULE_DESCRIPTION("CAN driver for Kvaser CAN/PCIe devices"); #define KVASER_PCIEFD_KCAN_FIFO_LAST_REG 0x180 #define KVASER_PCIEFD_KCAN_CTRL_REG 0x2c0 #define KVASER_PCIEFD_KCAN_CMD_REG 0x400 +#define KVASER_PCIEFD_KCAN_IOC_REG 0x404 #define KVASER_PCIEFD_KCAN_IEN_REG 0x408 #define KVASER_PCIEFD_KCAN_IRQ_REG 0x410 #define KVASER_PCIEFD_KCAN_TX_NR_PACKETS_REG 0x414 @@ -136,6 +135,9 @@ MODULE_DESCRIPTION("CAN driver for Kvaser CAN/PCIe devices"); /* Request status packet */ #define KVASER_PCIEFD_KCAN_CMD_SRQ BIT(0) +/* Control CAN LED, active low */ +#define KVASER_PCIEFD_KCAN_IOC_LED BIT(0) + /* Transmitter unaligned */ #define KVASER_PCIEFD_KCAN_IRQ_TAL BIT(17) /* Tx FIFO empty */ @@ -292,35 +294,6 @@ static void kvaser_pciefd_write_dma_map_sf2(struct kvaser_pciefd *pcie, static void kvaser_pciefd_write_dma_map_xilinx(struct kvaser_pciefd *pcie, dma_addr_t addr, int index); -struct kvaser_pciefd_address_offset { - u32 serdes; - u32 pci_ien; - u32 pci_irq; - u32 sysid; - u32 loopback; - u32 kcan_srb_fifo; - u32 kcan_srb; - u32 kcan_ch0; - u32 kcan_ch1; -}; - -struct kvaser_pciefd_dev_ops { - void (*kvaser_pciefd_write_dma_map)(struct kvaser_pciefd *pcie, - dma_addr_t addr, int index); -}; - -struct kvaser_pciefd_irq_mask { - u32 kcan_rx0; - u32 kcan_tx[KVASER_PCIEFD_MAX_CAN_CHANNELS]; - u32 all; -}; - -struct kvaser_pciefd_driver_data { - const struct kvaser_pciefd_address_offset *address_offset; - const struct kvaser_pciefd_irq_mask *irq_mask; - const struct kvaser_pciefd_dev_ops *ops; -}; - static const struct kvaser_pciefd_address_offset kvaser_pciefd_altera_address_offset = { .serdes = 0x1000, .pci_ien = 0x50, @@ -405,35 +378,6 @@ static const struct kvaser_pciefd_driver_data kvaser_pciefd_xilinx_driver_data = .ops = &kvaser_pciefd_xilinx_dev_ops, }; -struct kvaser_pciefd_can { - struct can_priv can; - struct kvaser_pciefd *kv_pcie; - void __iomem *reg_base; - struct can_berr_counter bec; - u8 cmd_seq; - u8 tx_max_count; - u8 tx_idx; - u8 ack_idx; - int err_rep_cnt; - unsigned int completed_tx_pkts; - unsigned int completed_tx_bytes; - spinlock_t lock; /* Locks sensitive registers (e.g. MODE) */ - struct timer_list bec_poll_timer; - struct completion start_comp, flush_comp; -}; - -struct kvaser_pciefd { - struct pci_dev *pci; - void __iomem *reg_base; - struct kvaser_pciefd_can *can[KVASER_PCIEFD_MAX_CAN_CHANNELS]; - const struct kvaser_pciefd_driver_data *driver_data; - void *dma_data[KVASER_PCIEFD_DMA_COUNT]; - u8 nr_channels; - u32 bus_freq; - u32 freq; - u32 freq_to_ticks_div; -}; - struct kvaser_pciefd_rx_packet { u32 header[2]; u64 timestamp; @@ -528,6 +472,16 @@ static inline void kvaser_pciefd_abort_flush_reset(struct kvaser_pciefd_can *can kvaser_pciefd_send_kcan_cmd(can, KVASER_PCIEFD_KCAN_CMD_AT); } +static inline void kvaser_pciefd_set_led(struct kvaser_pciefd_can *can, bool on) +{ + if (on) + can->ioc &= ~KVASER_PCIEFD_KCAN_IOC_LED; + else + can->ioc |= KVASER_PCIEFD_KCAN_IOC_LED; + + iowrite32(can->ioc, can->reg_base + KVASER_PCIEFD_KCAN_IOC_REG); +} + static void kvaser_pciefd_enable_err_gen(struct kvaser_pciefd_can *can) { u32 mode; @@ -953,8 +907,32 @@ static const struct net_device_ops kvaser_pciefd_netdev_ops = { .ndo_change_mtu = can_change_mtu, }; +static int kvaser_pciefd_set_phys_id(struct net_device *netdev, + enum ethtool_phys_id_state state) +{ + struct kvaser_pciefd_can *can = netdev_priv(netdev); + + switch (state) { + case ETHTOOL_ID_ACTIVE: + return 3; /* 3 On/Off cycles per second */ + + case ETHTOOL_ID_ON: + kvaser_pciefd_set_led(can, true); + return 0; + + case ETHTOOL_ID_OFF: + case ETHTOOL_ID_INACTIVE: + kvaser_pciefd_set_led(can, false); + return 0; + + default: + return -EINVAL; + } +} + static const struct ethtool_ops kvaser_pciefd_ethtool_ops = { .get_ts_info = can_ethtool_op_get_ts_info_hwts, + .set_phys_id = kvaser_pciefd_set_phys_id, }; static int kvaser_pciefd_setup_can_ctrls(struct kvaser_pciefd *pcie) @@ -965,6 +943,7 @@ static int kvaser_pciefd_setup_can_ctrls(struct kvaser_pciefd *pcie) struct net_device *netdev; struct kvaser_pciefd_can *can; u32 status, tx_nr_packets_max; + int ret; netdev = alloc_candev(sizeof(struct kvaser_pciefd_can), roundup_pow_of_two(KVASER_PCIEFD_CAN_TX_MAX_COUNT)); @@ -982,6 +961,7 @@ static int kvaser_pciefd_setup_can_ctrls(struct kvaser_pciefd *pcie) can->completed_tx_bytes = 0; can->bec.txerr = 0; can->bec.rxerr = 0; + can->can.dev->dev_port = i; init_completion(&can->start_comp); init_completion(&can->flush_comp); @@ -990,6 +970,9 @@ static int kvaser_pciefd_setup_can_ctrls(struct kvaser_pciefd *pcie) /* Disable Bus load reporting */ iowrite32(0, can->reg_base + KVASER_PCIEFD_KCAN_BUS_LOAD_REG); + can->ioc = ioread32(can->reg_base + KVASER_PCIEFD_KCAN_IOC_REG); + kvaser_pciefd_set_led(can, false); + tx_nr_packets_max = FIELD_GET(KVASER_PCIEFD_KCAN_TX_NR_PACKETS_MAX_MASK, ioread32(can->reg_base + KVASER_PCIEFD_KCAN_TX_NR_PACKETS_REG)); @@ -1031,6 +1014,11 @@ static int kvaser_pciefd_setup_can_ctrls(struct kvaser_pciefd *pcie) pcie->can[i] = can; kvaser_pciefd_pwm_start(can); + ret = kvaser_pciefd_devlink_port_register(can); + if (ret) { + dev_err(&pcie->pci->dev, "Failed to register devlink port\n"); + return ret; + } } return 0; @@ -1163,14 +1151,12 @@ static int kvaser_pciefd_setup_board(struct kvaser_pciefd *pcie) u32 version, srb_status, build; version = ioread32(KVASER_PCIEFD_SYSID_ADDR(pcie) + KVASER_PCIEFD_SYSID_VERSION_REG); + build = ioread32(KVASER_PCIEFD_SYSID_ADDR(pcie) + KVASER_PCIEFD_SYSID_BUILD_REG); pcie->nr_channels = min(KVASER_PCIEFD_MAX_CAN_CHANNELS, FIELD_GET(KVASER_PCIEFD_SYSID_VERSION_NR_CHAN_MASK, version)); - - build = ioread32(KVASER_PCIEFD_SYSID_ADDR(pcie) + KVASER_PCIEFD_SYSID_BUILD_REG); - dev_dbg(&pcie->pci->dev, "Version %lu.%lu.%lu\n", - FIELD_GET(KVASER_PCIEFD_SYSID_VERSION_MAJOR_MASK, version), - FIELD_GET(KVASER_PCIEFD_SYSID_VERSION_MINOR_MASK, version), - FIELD_GET(KVASER_PCIEFD_SYSID_BUILD_SEQ_MASK, build)); + pcie->fw_version.major = FIELD_GET(KVASER_PCIEFD_SYSID_VERSION_MAJOR_MASK, version); + pcie->fw_version.minor = FIELD_GET(KVASER_PCIEFD_SYSID_VERSION_MINOR_MASK, version); + pcie->fw_version.build = FIELD_GET(KVASER_PCIEFD_SYSID_BUILD_SEQ_MASK, build); srb_status = ioread32(KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_STAT_REG); if (!(srb_status & KVASER_PCIEFD_SRB_STAT_DMA)) { @@ -1752,6 +1738,7 @@ static void kvaser_pciefd_teardown_can_ctrls(struct kvaser_pciefd *pcie) if (can) { iowrite32(0, can->reg_base + KVASER_PCIEFD_KCAN_IEN_REG); kvaser_pciefd_pwm_stop(can); + kvaser_pciefd_devlink_port_unregister(can); free_candev(can->can.dev); } } @@ -1771,13 +1758,16 @@ static int kvaser_pciefd_probe(struct pci_dev *pdev, const struct pci_device_id *id) { int ret; + struct devlink *devlink; + struct device *dev = &pdev->dev; struct kvaser_pciefd *pcie; const struct kvaser_pciefd_irq_mask *irq_mask; - pcie = devm_kzalloc(&pdev->dev, sizeof(*pcie), GFP_KERNEL); - if (!pcie) + devlink = devlink_alloc(&kvaser_pciefd_devlink_ops, sizeof(*pcie), dev); + if (!devlink) return -ENOMEM; + pcie = devlink_priv(devlink); pci_set_drvdata(pdev, pcie); pcie->pci = pdev; pcie->driver_data = (const struct kvaser_pciefd_driver_data *)id->driver_data; @@ -1785,7 +1775,7 @@ static int kvaser_pciefd_probe(struct pci_dev *pdev, ret = pci_enable_device(pdev); if (ret) - return ret; + goto err_free_devlink; ret = pci_request_regions(pdev, KVASER_PCIEFD_DRV_NAME); if (ret) @@ -1813,7 +1803,7 @@ static int kvaser_pciefd_probe(struct pci_dev *pdev, ret = pci_alloc_irq_vectors(pcie->pci, 1, 1, PCI_IRQ_INTX | PCI_IRQ_MSI); if (ret < 0) { - dev_err(&pcie->pci->dev, "Failed to allocate IRQ vectors.\n"); + dev_err(dev, "Failed to allocate IRQ vectors.\n"); goto err_teardown_can_ctrls; } @@ -1826,7 +1816,7 @@ static int kvaser_pciefd_probe(struct pci_dev *pdev, ret = request_irq(pcie->pci->irq, kvaser_pciefd_irq_handler, IRQF_SHARED, KVASER_PCIEFD_DRV_NAME, pcie); if (ret) { - dev_err(&pcie->pci->dev, "Failed to request IRQ %d\n", pcie->pci->irq); + dev_err(dev, "Failed to request IRQ %d\n", pcie->pci->irq); goto err_pci_free_irq_vectors; } iowrite32(KVASER_PCIEFD_SRB_IRQ_DPD0 | KVASER_PCIEFD_SRB_IRQ_DPD1, @@ -1849,6 +1839,8 @@ static int kvaser_pciefd_probe(struct pci_dev *pdev, if (ret) goto err_free_irq; + devlink_register(devlink); + return 0; err_free_irq: @@ -1872,6 +1864,9 @@ err_release_regions: err_disable_pci: pci_disable_device(pdev); +err_free_devlink: + devlink_free(devlink); + return ret; } @@ -1886,6 +1881,7 @@ static void kvaser_pciefd_remove(struct pci_dev *pdev) unregister_candev(can->can.dev); timer_delete(&can->bec_poll_timer); kvaser_pciefd_pwm_stop(can); + kvaser_pciefd_devlink_port_unregister(can); } kvaser_pciefd_disable_irq_srcs(pcie); @@ -1895,9 +1891,11 @@ static void kvaser_pciefd_remove(struct pci_dev *pdev) for (i = 0; i < pcie->nr_channels; ++i) free_candev(pcie->can[i]->can.dev); + devlink_unregister(priv_to_devlink(pcie)); pci_iounmap(pdev, pcie->reg_base); pci_release_regions(pdev); pci_disable_device(pdev); + devlink_free(priv_to_devlink(pcie)); } static struct pci_driver kvaser_pciefd = { diff --git a/drivers/net/can/kvaser_pciefd/kvaser_pciefd_devlink.c b/drivers/net/can/kvaser_pciefd/kvaser_pciefd_devlink.c new file mode 100644 index 000000000000..1d61a8b0eeba --- /dev/null +++ b/drivers/net/can/kvaser_pciefd/kvaser_pciefd_devlink.c @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +/* kvaser_pciefd devlink functions + * + * Copyright (C) 2025 KVASER AB, Sweden. All rights reserved. + */ +#include "kvaser_pciefd.h" + +#include <linux/netdevice.h> +#include <net/devlink.h> + +static int kvaser_pciefd_devlink_info_get(struct devlink *devlink, + struct devlink_info_req *req, + struct netlink_ext_ack *extack) +{ + struct kvaser_pciefd *pcie = devlink_priv(devlink); + char buf[] = "xxx.xxx.xxxxx"; + int ret; + + if (pcie->fw_version.major) { + snprintf(buf, sizeof(buf), "%u.%u.%u", + pcie->fw_version.major, + pcie->fw_version.minor, + pcie->fw_version.build); + ret = devlink_info_version_running_put(req, + DEVLINK_INFO_VERSION_GENERIC_FW, + buf); + if (ret) + return ret; + } + + return 0; +} + +const struct devlink_ops kvaser_pciefd_devlink_ops = { + .info_get = kvaser_pciefd_devlink_info_get, +}; + +int kvaser_pciefd_devlink_port_register(struct kvaser_pciefd_can *can) +{ + int ret; + struct devlink_port_attrs attrs = { + .flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL, + .phys.port_number = can->can.dev->dev_port, + }; + devlink_port_attrs_set(&can->devlink_port, &attrs); + + ret = devlink_port_register(priv_to_devlink(can->kv_pcie), + &can->devlink_port, can->can.dev->dev_port); + if (ret) + return ret; + + SET_NETDEV_DEVLINK_PORT(can->can.dev, &can->devlink_port); + + return 0; +} + +void kvaser_pciefd_devlink_port_unregister(struct kvaser_pciefd_can *can) +{ + devlink_port_unregister(&can->devlink_port); +} diff --git a/drivers/net/can/rcar/rcar_can.c b/drivers/net/can/rcar/rcar_can.c index 2b7dd359f27b..64e664f5adcc 100644 --- a/drivers/net/can/rcar/rcar_can.c +++ b/drivers/net/can/rcar/rcar_can.c @@ -834,7 +834,7 @@ static void rcar_can_remove(struct platform_device *pdev) free_candev(ndev); } -static int __maybe_unused rcar_can_suspend(struct device *dev) +static int rcar_can_suspend(struct device *dev) { struct net_device *ndev = dev_get_drvdata(dev); struct rcar_can_priv *priv = netdev_priv(ndev); @@ -857,7 +857,7 @@ static int __maybe_unused rcar_can_suspend(struct device *dev) return 0; } -static int __maybe_unused rcar_can_resume(struct device *dev) +static int rcar_can_resume(struct device *dev) { struct net_device *ndev = dev_get_drvdata(dev); struct rcar_can_priv *priv = netdev_priv(ndev); @@ -886,7 +886,8 @@ static int __maybe_unused rcar_can_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(rcar_can_pm_ops, rcar_can_suspend, rcar_can_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(rcar_can_pm_ops, rcar_can_suspend, + rcar_can_resume); static const struct of_device_id rcar_can_of_table[] __maybe_unused = { { .compatible = "renesas,can-r8a7778" }, @@ -904,7 +905,7 @@ static struct platform_driver rcar_can_driver = { .driver = { .name = RCAR_CAN_DRV_NAME, .of_match_table = of_match_ptr(rcar_can_of_table), - .pm = &rcar_can_pm_ops, + .pm = pm_sleep_ptr(&rcar_can_pm_ops), }, .probe = rcar_can_probe, .remove = rcar_can_remove, diff --git a/drivers/net/can/rcar/rcar_canfd.c b/drivers/net/can/rcar/rcar_canfd.c index 7f10213738e5..b3c8c592fb0e 100644 --- a/drivers/net/can/rcar/rcar_canfd.c +++ b/drivers/net/can/rcar/rcar_canfd.c @@ -191,9 +191,19 @@ /* RSCFDnCFDCmFDCFG */ #define RCANFD_GEN4_FDCFG_CLOE BIT(30) #define RCANFD_GEN4_FDCFG_FDOE BIT(28) +#define RCANFD_FDCFG_TDCO GENMASK(23, 16) #define RCANFD_FDCFG_TDCE BIT(9) #define RCANFD_FDCFG_TDCOC BIT(8) -#define RCANFD_FDCFG_TDCO(x) (((x) & 0x7f) >> 16) + +/* RSCFDnCFDCmFDSTS */ +#define RCANFD_FDSTS_SOC GENMASK(31, 24) +#define RCANFD_FDSTS_EOC GENMASK(23, 16) +#define RCANFD_GEN4_FDSTS_TDCVF BIT(15) +#define RCANFD_GEN4_FDSTS_PNSTS GENMASK(13, 12) +#define RCANFD_FDSTS_SOCO BIT(9) +#define RCANFD_FDSTS_EOCO BIT(8) +#define RCANFD_FDSTS_TDCVF BIT(7) +#define RCANFD_FDSTS_TDCR GENMASK(7, 0) /* RSCFDnCFDRFCCx */ #define RCANFD_RFCC_RFIM BIT(12) @@ -214,8 +224,6 @@ /* RSCFDnCFDRFPTRx */ #define RCANFD_RFPTR_RFDLC(x) (((x) >> 28) & 0xf) -#define RCANFD_RFPTR_RFPTR(x) (((x) >> 16) & 0xfff) -#define RCANFD_RFPTR_RFTS(x) (((x) >> 0) & 0xffff) /* RSCFDnCFDRFFDSTSx */ #define RCANFD_RFFDSTS_RFFDF BIT(2) @@ -247,12 +255,9 @@ /* RSCFDnCFDCFIDk */ #define RCANFD_CFID_CFIDE BIT(31) #define RCANFD_CFID_CFRTR BIT(30) -#define RCANFD_CFID_CFID_MASK(x) ((x) & 0x1fffffff) /* RSCFDnCFDCFPTRk */ #define RCANFD_CFPTR_CFDLC(x) (((x) & 0xf) << 28) -#define RCANFD_CFPTR_CFPTR(x) (((x) & 0xfff) << 16) -#define RCANFD_CFPTR_CFTS(x) (((x) & 0xff) << 0) /* RSCFDnCFDCFFDCSTSk */ #define RCANFD_CFFDCSTS_CFFDF BIT(2) @@ -318,59 +323,6 @@ #define RCANFD_CFPCTR(gpriv, ch, idx) \ ((gpriv)->info->regs->cfpctr + (0x0c * (ch)) + (0x04 * (idx))) -/* RSCFDnCFDFESTS / RSCFDnFESTS */ -#define RCANFD_FESTS (0x0238) -/* RSCFDnCFDFFSTS / RSCFDnFFSTS */ -#define RCANFD_FFSTS (0x023c) -/* RSCFDnCFDFMSTS / RSCFDnFMSTS */ -#define RCANFD_FMSTS (0x0240) -/* RSCFDnCFDRFISTS / RSCFDnRFISTS */ -#define RCANFD_RFISTS (0x0244) -/* RSCFDnCFDCFRISTS / RSCFDnCFRISTS */ -#define RCANFD_CFRISTS (0x0248) -/* RSCFDnCFDCFTISTS / RSCFDnCFTISTS */ -#define RCANFD_CFTISTS (0x024c) - -/* RSCFDnCFDTMCp / RSCFDnTMCp */ -#define RCANFD_TMC(p) (0x0250 + (0x01 * (p))) -/* RSCFDnCFDTMSTSp / RSCFDnTMSTSp */ -#define RCANFD_TMSTS(p) (0x02d0 + (0x01 * (p))) - -/* RSCFDnCFDTMTRSTSp / RSCFDnTMTRSTSp */ -#define RCANFD_TMTRSTS(y) (0x0350 + (0x04 * (y))) -/* RSCFDnCFDTMTARSTSp / RSCFDnTMTARSTSp */ -#define RCANFD_TMTARSTS(y) (0x0360 + (0x04 * (y))) -/* RSCFDnCFDTMTCSTSp / RSCFDnTMTCSTSp */ -#define RCANFD_TMTCSTS(y) (0x0370 + (0x04 * (y))) -/* RSCFDnCFDTMTASTSp / RSCFDnTMTASTSp */ -#define RCANFD_TMTASTS(y) (0x0380 + (0x04 * (y))) -/* RSCFDnCFDTMIECy / RSCFDnTMIECy */ -#define RCANFD_TMIEC(y) (0x0390 + (0x04 * (y))) - -/* RSCFDnCFDTXQCCm / RSCFDnTXQCCm */ -#define RCANFD_TXQCC(m) (0x03a0 + (0x04 * (m))) -/* RSCFDnCFDTXQSTSm / RSCFDnTXQSTSm */ -#define RCANFD_TXQSTS(m) (0x03c0 + (0x04 * (m))) -/* RSCFDnCFDTXQPCTRm / RSCFDnTXQPCTRm */ -#define RCANFD_TXQPCTR(m) (0x03e0 + (0x04 * (m))) - -/* RSCFDnCFDTHLCCm / RSCFDnTHLCCm */ -#define RCANFD_THLCC(m) (0x0400 + (0x04 * (m))) -/* RSCFDnCFDTHLSTSm / RSCFDnTHLSTSm */ -#define RCANFD_THLSTS(m) (0x0420 + (0x04 * (m))) -/* RSCFDnCFDTHLPCTRm / RSCFDnTHLPCTRm */ -#define RCANFD_THLPCTR(m) (0x0440 + (0x04 * (m))) - -/* RSCFDnCFDGTINTSTS0 / RSCFDnGTINTSTS0 */ -#define RCANFD_GTINTSTS0 (0x0460) -/* RSCFDnCFDGTINTSTS1 / RSCFDnGTINTSTS1 */ -#define RCANFD_GTINTSTS1 (0x0464) -/* RSCFDnCFDGTSTCFG / RSCFDnGTSTCFG */ -#define RCANFD_GTSTCFG (0x0468) -/* RSCFDnCFDGTSTCTR / RSCFDnGTSTCTR */ -#define RCANFD_GTSTCTR (0x046c) -/* RSCFDnCFDGLOCKK / RSCFDnGLOCKK */ -#define RCANFD_GLOCKK (0x047c) /* RSCFDnCFDGRMCFG */ #define RCANFD_GRMCFG (0x04fc) @@ -388,12 +340,6 @@ /* RSCFDnGAFLXXXj offset */ #define RCANFD_C_GAFL_OFFSET (0x0500) -/* RSCFDnRMXXXq -> RCANFD_C_RMXXX(q) */ -#define RCANFD_C_RMID(q) (0x0600 + (0x10 * (q))) -#define RCANFD_C_RMPTR(q) (0x0604 + (0x10 * (q))) -#define RCANFD_C_RMDF0(q) (0x0608 + (0x10 * (q))) -#define RCANFD_C_RMDF1(q) (0x060c + (0x10 * (q))) - /* RSCFDnRFXXx -> RCANFD_C_RFXX(x) */ #define RCANFD_C_RFOFFSET (0x0e00) #define RCANFD_C_RFID(x) (RCANFD_C_RFOFFSET + (0x10 * (x))) @@ -413,40 +359,24 @@ #define RCANFD_C_CFDF(ch, idx, df) \ (RCANFD_C_CFOFFSET + 0x08 + (0x30 * (ch)) + (0x10 * (idx)) + (0x04 * (df))) -/* RSCFDnTMXXp -> RCANFD_C_TMXX(p) */ -#define RCANFD_C_TMID(p) (0x1000 + (0x10 * (p))) -#define RCANFD_C_TMPTR(p) (0x1004 + (0x10 * (p))) -#define RCANFD_C_TMDF0(p) (0x1008 + (0x10 * (p))) -#define RCANFD_C_TMDF1(p) (0x100c + (0x10 * (p))) - -/* RSCFDnTHLACCm */ -#define RCANFD_C_THLACC(m) (0x1800 + (0x04 * (m))) -/* RSCFDnRPGACCr */ -#define RCANFD_C_RPGACC(r) (0x1900 + (0x04 * (r))) - /* R-Car Gen4 Classical and CAN FD mode specific register map */ -#define RCANFD_GEN4_FDCFG(m) (0x1404 + (0x20 * (m))) - #define RCANFD_GEN4_GAFL_OFFSET (0x1800) /* CAN FD mode specific register map */ -/* RSCFDnCFDCmXXX -> RCANFD_F_XXX(m) */ -#define RCANFD_F_DCFG(gpriv, m) ((gpriv)->info->regs->f_dcfg + (0x20 * (m))) -#define RCANFD_F_CFDCFG(m) (0x0504 + (0x20 * (m))) -#define RCANFD_F_CFDCTR(m) (0x0508 + (0x20 * (m))) -#define RCANFD_F_CFDSTS(m) (0x050c + (0x20 * (m))) -#define RCANFD_F_CFDCRC(m) (0x0510 + (0x20 * (m))) +/* RSCFDnCFDCmXXX -> gpriv->fcbase[m].xxx */ +struct rcar_canfd_f_c { + u32 dcfg; + u32 cfdcfg; + u32 cfdctr; + u32 cfdsts; + u32 cfdcrc; + u32 pad[3]; +}; /* RSCFDnCFDGAFLXXXj offset */ #define RCANFD_F_GAFL_OFFSET (0x1000) -/* RSCFDnCFDRMXXXq -> RCANFD_F_RMXXX(q) */ -#define RCANFD_F_RMID(q) (0x2000 + (0x20 * (q))) -#define RCANFD_F_RMPTR(q) (0x2004 + (0x20 * (q))) -#define RCANFD_F_RMFDSTS(q) (0x2008 + (0x20 * (q))) -#define RCANFD_F_RMDF(q, b) (0x200c + (0x04 * (b)) + (0x20 * (q))) - /* RSCFDnCFDRFXXx -> RCANFD_F_RFXX(x) */ #define RCANFD_F_RFOFFSET(gpriv) ((gpriv)->info->regs->rfoffset) #define RCANFD_F_RFID(gpriv, x) (RCANFD_F_RFOFFSET(gpriv) + (0x80 * (x))) @@ -471,23 +401,11 @@ (RCANFD_F_CFOFFSET(gpriv) + 0x0c + (0x180 * (ch)) + (0x80 * (idx)) + \ (0x04 * (df))) -/* RSCFDnCFDTMXXp -> RCANFD_F_TMXX(p) */ -#define RCANFD_F_TMID(p) (0x4000 + (0x20 * (p))) -#define RCANFD_F_TMPTR(p) (0x4004 + (0x20 * (p))) -#define RCANFD_F_TMFDCTR(p) (0x4008 + (0x20 * (p))) -#define RCANFD_F_TMDF(p, b) (0x400c + (0x20 * (p)) + (0x04 * (b))) - -/* RSCFDnCFDTHLACCm */ -#define RCANFD_F_THLACC(m) (0x6000 + (0x04 * (m))) -/* RSCFDnCFDRPGACCr */ -#define RCANFD_F_RPGACC(r) (0x6400 + (0x04 * (r))) - /* Constants */ #define RCANFD_FIFO_DEPTH 8 /* Tx FIFO depth */ #define RCANFD_NAPI_WEIGHT 8 /* Rx poll quota */ #define RCANFD_NUM_CHANNELS 8 /* Eight channels max */ -#define RCANFD_CHANNELS_MASK BIT((RCANFD_NUM_CHANNELS) - 1) #define RCANFD_GAFL_PAGENUM(entry) ((entry) / 16) #define RCANFD_CHANNEL_NUMRULES 1 /* only one rule per channel */ @@ -510,7 +428,7 @@ struct rcar_canfd_regs { u16 cfcc; /* Common FIFO Configuration/Control Register */ u16 cfsts; /* Common FIFO Status Register */ u16 cfpctr; /* Common FIFO Pointer Control Register */ - u16 f_dcfg; /* Global FD Configuration Register */ + u16 coffset; /* Channel Data Bitrate Configuration Register */ u16 rfoffset; /* Receive FIFO buffer access ID register */ u16 cfoffset; /* Transmit/receive FIFO buffer access ID register */ }; @@ -529,6 +447,7 @@ struct rcar_canfd_shift_data { struct rcar_canfd_hw_info { const struct can_bittiming_const *nom_bittiming; const struct can_bittiming_const *data_bittiming; + const struct can_tdc_const *tdc_const; const struct rcar_canfd_regs *regs; const struct rcar_canfd_shift_data *sh; u8 rnc_field_width; @@ -562,6 +481,7 @@ struct rcar_canfd_channel { struct rcar_canfd_global { struct rcar_canfd_channel *ch[RCANFD_NUM_CHANNELS]; void __iomem *base; /* Register base address */ + struct rcar_canfd_f_c __iomem *fcbase; struct platform_device *pdev; /* Respective platform device */ struct clk *clkp; /* Peripheral clock */ struct clk *can_clk; /* fCAN clock */ @@ -636,12 +556,31 @@ static const struct can_bittiming_const rcar_canfd_bittiming_const = { .brp_inc = 1, }; +/* CAN FD Transmission Delay Compensation constants */ +static const struct can_tdc_const rcar_canfd_gen3_tdc_const = { + .tdcv_min = 1, + .tdcv_max = 128, + .tdco_min = 1, + .tdco_max = 128, + .tdcf_min = 0, /* Filter window not supported */ + .tdcf_max = 0, +}; + +static const struct can_tdc_const rcar_canfd_gen4_tdc_const = { + .tdcv_min = 1, + .tdcv_max = 256, + .tdco_min = 1, + .tdco_max = 256, + .tdcf_min = 0, /* Filter window not supported */ + .tdcf_max = 0, +}; + static const struct rcar_canfd_regs rcar_gen3_regs = { .rfcc = 0x00b8, .cfcc = 0x0118, .cfsts = 0x0178, .cfpctr = 0x01d8, - .f_dcfg = 0x0500, + .coffset = 0x0500, .rfoffset = 0x3000, .cfoffset = 0x3400, }; @@ -651,7 +590,7 @@ static const struct rcar_canfd_regs rcar_gen4_regs = { .cfcc = 0x0120, .cfsts = 0x01e0, .cfpctr = 0x0240, - .f_dcfg = 0x1400, + .coffset = 0x1400, .rfoffset = 0x6000, .cfoffset = 0x6400, }; @@ -681,6 +620,7 @@ static const struct rcar_canfd_shift_data rcar_gen4_shift_data = { static const struct rcar_canfd_hw_info rcar_gen3_hw_info = { .nom_bittiming = &rcar_canfd_gen3_nom_bittiming_const, .data_bittiming = &rcar_canfd_gen3_data_bittiming_const, + .tdc_const = &rcar_canfd_gen3_tdc_const, .regs = &rcar_gen3_regs, .sh = &rcar_gen3_shift_data, .rnc_field_width = 8, @@ -697,6 +637,7 @@ static const struct rcar_canfd_hw_info rcar_gen3_hw_info = { static const struct rcar_canfd_hw_info rcar_gen4_hw_info = { .nom_bittiming = &rcar_canfd_gen4_nom_bittiming_const, .data_bittiming = &rcar_canfd_gen4_data_bittiming_const, + .tdc_const = &rcar_canfd_gen4_tdc_const, .regs = &rcar_gen4_regs, .sh = &rcar_gen4_shift_data, .rnc_field_width = 16, @@ -713,6 +654,7 @@ static const struct rcar_canfd_hw_info rcar_gen4_hw_info = { static const struct rcar_canfd_hw_info rzg2l_hw_info = { .nom_bittiming = &rcar_canfd_gen3_nom_bittiming_const, .data_bittiming = &rcar_canfd_gen3_data_bittiming_const, + .tdc_const = &rcar_canfd_gen3_tdc_const, .regs = &rcar_gen3_regs, .sh = &rcar_gen3_shift_data, .rnc_field_width = 8, @@ -729,6 +671,7 @@ static const struct rcar_canfd_hw_info rzg2l_hw_info = { static const struct rcar_canfd_hw_info r9a09g047_hw_info = { .nom_bittiming = &rcar_canfd_gen4_nom_bittiming_const, .data_bittiming = &rcar_canfd_gen4_data_bittiming_const, + .tdc_const = &rcar_canfd_gen4_tdc_const, .regs = &rcar_gen4_regs, .sh = &rcar_gen4_shift_data, .rnc_field_width = 16, @@ -778,26 +721,36 @@ static void rcar_canfd_update_bit(void __iomem *base, u32 reg, rcar_canfd_update(mask, val, base + reg); } +static void rcar_canfd_set_bit_reg(void __iomem *addr, u32 val) +{ + rcar_canfd_update(val, val, addr); +} + +static void rcar_canfd_update_bit_reg(void __iomem *addr, u32 mask, u32 val) +{ + rcar_canfd_update(mask, val, addr); +} + static void rcar_canfd_get_data(struct rcar_canfd_channel *priv, struct canfd_frame *cf, u32 off) { + u32 *data = (u32 *)cf->data; u32 i, lwords; lwords = DIV_ROUND_UP(cf->len, sizeof(u32)); for (i = 0; i < lwords; i++) - *((u32 *)cf->data + i) = - rcar_canfd_read(priv->base, off + i * sizeof(u32)); + data[i] = rcar_canfd_read(priv->base, off + i * sizeof(u32)); } static void rcar_canfd_put_data(struct rcar_canfd_channel *priv, struct canfd_frame *cf, u32 off) { + const u32 *data = (u32 *)cf->data; u32 i, lwords; lwords = DIV_ROUND_UP(cf->len, sizeof(u32)); for (i = 0; i < lwords; i++) - rcar_canfd_write(priv->base, off + i * sizeof(u32), - *((u32 *)cf->data + i)); + rcar_canfd_write(priv->base, off + i * sizeof(u32), data[i]); } static void rcar_canfd_tx_failure_cleanup(struct net_device *ndev) @@ -808,8 +761,8 @@ static void rcar_canfd_tx_failure_cleanup(struct net_device *ndev) can_free_echo_skb(ndev, i, NULL); } -static void rcar_canfd_setrnc(struct rcar_canfd_global *gpriv, unsigned int ch, - unsigned int num_rules) +static void rcar_canfd_set_rnc(struct rcar_canfd_global *gpriv, unsigned int ch, + unsigned int num_rules) { unsigned int rnc_stride = 32 / gpriv->info->rnc_field_width; unsigned int shift = 32 - (ch % rnc_stride + 1) * gpriv->info->rnc_field_width; @@ -827,8 +780,7 @@ static void rcar_canfd_set_mode(struct rcar_canfd_global *gpriv) for_each_set_bit(ch, &gpriv->channels_mask, gpriv->info->max_channels) - rcar_canfd_set_bit(gpriv->base, RCANFD_GEN4_FDCFG(ch), - val); + rcar_canfd_set_bit_reg(&gpriv->fcbase[ch].cfdcfg, val); } else { if (gpriv->fdmode) rcar_canfd_set_bit(gpriv->base, RCANFD_GRMCFG, @@ -841,6 +793,7 @@ static void rcar_canfd_set_mode(struct rcar_canfd_global *gpriv) static int rcar_canfd_reset_controller(struct rcar_canfd_global *gpriv) { + struct device *dev = &gpriv->pdev->dev; u32 sts, ch; int err; @@ -850,7 +803,7 @@ static int rcar_canfd_reset_controller(struct rcar_canfd_global *gpriv) err = readl_poll_timeout((gpriv->base + RCANFD_GSTS), sts, !(sts & RCANFD_GSTS_GRAMINIT), 2, 500000); if (err) { - dev_dbg(&gpriv->pdev->dev, "global raminit failed\n"); + dev_dbg(dev, "global raminit failed\n"); return err; } @@ -863,7 +816,7 @@ static int rcar_canfd_reset_controller(struct rcar_canfd_global *gpriv) err = readl_poll_timeout((gpriv->base + RCANFD_GSTS), sts, (sts & RCANFD_GSTS_GRSTSTS), 2, 500000); if (err) { - dev_dbg(&gpriv->pdev->dev, "global reset failed\n"); + dev_dbg(dev, "global reset failed\n"); return err; } @@ -887,8 +840,7 @@ static int rcar_canfd_reset_controller(struct rcar_canfd_global *gpriv) (sts & RCANFD_CSTS_CRSTSTS), 2, 500000); if (err) { - dev_dbg(&gpriv->pdev->dev, - "channel %u reset failed\n", ch); + dev_dbg(dev, "channel %u reset failed\n", ch); return err; } } @@ -938,7 +890,7 @@ static void rcar_canfd_configure_afl_rules(struct rcar_canfd_global *gpriv, RCANFD_GAFLECTR_AFLDAE)); /* Write number of rules for channel */ - rcar_canfd_setrnc(gpriv, ch, num_rules); + rcar_canfd_set_rnc(gpriv, ch, num_rules); if (gpriv->info->shared_can_regs) offset = RCANFD_GEN4_GAFL_OFFSET; else if (gpriv->fdmode) @@ -1436,14 +1388,17 @@ static irqreturn_t rcar_canfd_channel_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static void rcar_canfd_set_bittiming(struct net_device *dev) +static void rcar_canfd_set_bittiming(struct net_device *ndev) { - struct rcar_canfd_channel *priv = netdev_priv(dev); + u32 mask = RCANFD_FDCFG_TDCO | RCANFD_FDCFG_TDCE | RCANFD_FDCFG_TDCOC; + struct rcar_canfd_channel *priv = netdev_priv(ndev); struct rcar_canfd_global *gpriv = priv->gpriv; const struct can_bittiming *bt = &priv->can.bittiming; const struct can_bittiming *dbt = &priv->can.fd.data_bittiming; + const struct can_tdc_const *tdc_const = priv->can.fd.tdc_const; + const struct can_tdc *tdc = &priv->can.fd.tdc; + u32 cfg, tdcmode = 0, tdco = 0; u16 brp, sjw, tseg1, tseg2; - u32 cfg; u32 ch = priv->channel; /* Nominal bit timing settings */ @@ -1452,46 +1407,43 @@ static void rcar_canfd_set_bittiming(struct net_device *dev) tseg1 = bt->prop_seg + bt->phase_seg1 - 1; tseg2 = bt->phase_seg2 - 1; - if (priv->can.ctrlmode & CAN_CTRLMODE_FD) { - /* CAN FD only mode */ + if ((priv->can.ctrlmode & CAN_CTRLMODE_FD) || gpriv->info->shared_can_regs) { cfg = (RCANFD_NCFG_NTSEG1(gpriv, tseg1) | RCANFD_NCFG_NBRP(brp) | RCANFD_NCFG_NSJW(gpriv, sjw) | RCANFD_NCFG_NTSEG2(gpriv, tseg2)); + } else { + cfg = (RCANFD_CFG_TSEG1(tseg1) | RCANFD_CFG_BRP(brp) | + RCANFD_CFG_SJW(sjw) | RCANFD_CFG_TSEG2(tseg2)); + } - rcar_canfd_write(priv->base, RCANFD_CCFG(ch), cfg); - netdev_dbg(priv->ndev, "nrate: brp %u, sjw %u, tseg1 %u, tseg2 %u\n", - brp, sjw, tseg1, tseg2); - - /* Data bit timing settings */ - brp = dbt->brp - 1; - sjw = dbt->sjw - 1; - tseg1 = dbt->prop_seg + dbt->phase_seg1 - 1; - tseg2 = dbt->phase_seg2 - 1; - - cfg = (RCANFD_DCFG_DTSEG1(gpriv, tseg1) | RCANFD_DCFG_DBRP(brp) | - RCANFD_DCFG_DSJW(gpriv, sjw) | RCANFD_DCFG_DTSEG2(gpriv, tseg2)); + rcar_canfd_write(priv->base, RCANFD_CCFG(ch), cfg); - rcar_canfd_write(priv->base, RCANFD_F_DCFG(gpriv, ch), cfg); - netdev_dbg(priv->ndev, "drate: brp %u, sjw %u, tseg1 %u, tseg2 %u\n", - brp, sjw, tseg1, tseg2); - } else { - /* Classical CAN only mode */ - if (gpriv->info->shared_can_regs) { - cfg = (RCANFD_NCFG_NTSEG1(gpriv, tseg1) | - RCANFD_NCFG_NBRP(brp) | - RCANFD_NCFG_NSJW(gpriv, sjw) | - RCANFD_NCFG_NTSEG2(gpriv, tseg2)); - } else { - cfg = (RCANFD_CFG_TSEG1(tseg1) | - RCANFD_CFG_BRP(brp) | - RCANFD_CFG_SJW(sjw) | - RCANFD_CFG_TSEG2(tseg2)); - } + if (!(priv->can.ctrlmode & CAN_CTRLMODE_FD)) + return; - rcar_canfd_write(priv->base, RCANFD_CCFG(ch), cfg); - netdev_dbg(priv->ndev, - "rate: brp %u, sjw %u, tseg1 %u, tseg2 %u\n", - brp, sjw, tseg1, tseg2); + /* Data bit timing settings */ + brp = dbt->brp - 1; + sjw = dbt->sjw - 1; + tseg1 = dbt->prop_seg + dbt->phase_seg1 - 1; + tseg2 = dbt->phase_seg2 - 1; + + cfg = (RCANFD_DCFG_DTSEG1(gpriv, tseg1) | RCANFD_DCFG_DBRP(brp) | + RCANFD_DCFG_DSJW(gpriv, sjw) | RCANFD_DCFG_DTSEG2(gpriv, tseg2)); + + writel(cfg, &gpriv->fcbase[ch].dcfg); + + /* Transceiver Delay Compensation */ + if (priv->can.ctrlmode & CAN_CTRLMODE_TDC_AUTO) { + /* TDC enabled, measured + offset */ + tdcmode = RCANFD_FDCFG_TDCE; + tdco = tdc->tdco - 1; + } else if (priv->can.ctrlmode & CAN_CTRLMODE_TDC_MANUAL) { + /* TDC enabled, offset only */ + tdcmode = RCANFD_FDCFG_TDCE | RCANFD_FDCFG_TDCOC; + tdco = min(tdc->tdcv + tdc->tdco, tdc_const->tdco_max) - 1; } + + rcar_canfd_update_bit_reg(&gpriv->fcbase[ch].cfdcfg, mask, + tdcmode | FIELD_PREP(RCANFD_FDCFG_TDCO, tdco)); } static int rcar_canfd_start(struct net_device *ndev) @@ -1691,7 +1643,8 @@ static netdev_tx_t rcar_canfd_start_xmit(struct sk_buff *skb, static void rcar_canfd_rx_pkt(struct rcar_canfd_channel *priv) { - struct net_device_stats *stats = &priv->ndev->stats; + struct net_device *ndev = priv->ndev; + struct net_device_stats *stats = &ndev->stats; struct rcar_canfd_global *gpriv = priv->gpriv; struct canfd_frame *cf; struct sk_buff *skb; @@ -1707,14 +1660,13 @@ static void rcar_canfd_rx_pkt(struct rcar_canfd_channel *priv) if ((priv->can.ctrlmode & CAN_CTRLMODE_FD) && sts & RCANFD_RFFDSTS_RFFDF) - skb = alloc_canfd_skb(priv->ndev, &cf); + skb = alloc_canfd_skb(ndev, &cf); else - skb = alloc_can_skb(priv->ndev, - (struct can_frame **)&cf); + skb = alloc_can_skb(ndev, (struct can_frame **)&cf); } else { id = rcar_canfd_read(priv->base, RCANFD_C_RFID(ridx)); dlc = rcar_canfd_read(priv->base, RCANFD_C_RFPTR(ridx)); - skb = alloc_can_skb(priv->ndev, (struct can_frame **)&cf); + skb = alloc_can_skb(ndev, (struct can_frame **)&cf); } if (!skb) { @@ -1735,7 +1687,7 @@ static void rcar_canfd_rx_pkt(struct rcar_canfd_channel *priv) if (sts & RCANFD_RFFDSTS_RFESI) { cf->flags |= CANFD_ESI; - netdev_dbg(priv->ndev, "ESI Error\n"); + netdev_dbg(ndev, "ESI Error\n"); } if (!(sts & RCANFD_RFFDSTS_RFFDF) && (id & RCANFD_RFID_RFRTR)) { @@ -1802,6 +1754,29 @@ static int rcar_canfd_rx_poll(struct napi_struct *napi, int quota) return num_pkts; } +static unsigned int rcar_canfd_get_tdcr(struct rcar_canfd_global *gpriv, + unsigned int ch) +{ + u32 sts = readl(&gpriv->fcbase[ch].cfdsts); + u32 tdcr = FIELD_GET(RCANFD_FDSTS_TDCR, sts); + + return tdcr & (gpriv->info->tdc_const->tdcv_max - 1); +} + +static int rcar_canfd_get_auto_tdcv(const struct net_device *ndev, u32 *tdcv) +{ + struct rcar_canfd_channel *priv = netdev_priv(ndev); + u32 tdco = priv->can.fd.tdc.tdco; + u32 tdcr; + + /* Transceiver Delay Compensation Result */ + tdcr = rcar_canfd_get_tdcr(priv->gpriv, priv->channel) + 1; + + *tdcv = tdcr < tdco ? 0 : tdcr - tdco; + + return 0; +} + static int rcar_canfd_do_set_mode(struct net_device *ndev, enum can_mode mode) { int err; @@ -1818,10 +1793,10 @@ static int rcar_canfd_do_set_mode(struct net_device *ndev, enum can_mode mode) } } -static int rcar_canfd_get_berr_counter(const struct net_device *dev, +static int rcar_canfd_get_berr_counter(const struct net_device *ndev, struct can_berr_counter *bec) { - struct rcar_canfd_channel *priv = netdev_priv(dev); + struct rcar_canfd_channel *priv = netdev_priv(ndev); u32 val, ch = priv->channel; /* Peripheral clock is already enabled in probe */ @@ -1924,12 +1899,17 @@ static int rcar_canfd_channel_probe(struct rcar_canfd_global *gpriv, u32 ch, if (gpriv->fdmode) { priv->can.bittiming_const = gpriv->info->nom_bittiming; priv->can.fd.data_bittiming_const = gpriv->info->data_bittiming; + priv->can.fd.tdc_const = gpriv->info->tdc_const; /* Controller starts in CAN FD only mode */ err = can_set_static_ctrlmode(ndev, CAN_CTRLMODE_FD); if (err) goto fail; - priv->can.ctrlmode_supported = CAN_CTRLMODE_BERR_REPORTING; + + priv->can.ctrlmode_supported = CAN_CTRLMODE_BERR_REPORTING | + CAN_CTRLMODE_TDC_AUTO | + CAN_CTRLMODE_TDC_MANUAL; + priv->can.fd.do_get_auto_tdcv = rcar_canfd_get_auto_tdcv; } else { /* Controller starts in Classical CAN only mode */ priv->can.bittiming_const = &rcar_canfd_bittiming_const; @@ -2086,6 +2066,7 @@ static int rcar_canfd_probe(struct platform_device *pdev) goto fail_dev; } gpriv->base = addr; + gpriv->fcbase = addr + gpriv->info->regs->coffset; /* Request IRQ that's common for both channels */ if (info->shared_global_irqs) { diff --git a/drivers/net/can/rockchip/rockchip_canfd-timestamp.c b/drivers/net/can/rockchip/rockchip_canfd-timestamp.c index fa85a75be65a..72774cd2f94b 100644 --- a/drivers/net/can/rockchip/rockchip_canfd-timestamp.c +++ b/drivers/net/can/rockchip/rockchip_canfd-timestamp.c @@ -8,7 +8,7 @@ #include "rockchip_canfd.h" -static u64 rkcanfd_timestamp_read(const struct cyclecounter *cc) +static u64 rkcanfd_timestamp_read(struct cyclecounter *cc) { const struct rkcanfd_priv *priv = container_of(cc, struct rkcanfd_priv, cc); diff --git a/drivers/net/can/sja1000/Kconfig b/drivers/net/can/sja1000/Kconfig index 2f516cc6d22c..e061e35769bf 100644 --- a/drivers/net/can/sja1000/Kconfig +++ b/drivers/net/can/sja1000/Kconfig @@ -105,7 +105,7 @@ config CAN_SJA1000_PLATFORM config CAN_TSCAN1 tristate "TS-CAN1 PC104 boards" - depends on ISA + depends on (ISA && PC104) || (COMPILE_TEST && HAS_IOPORT) help This driver is for Technologic Systems' TSCAN-1 PC104 boards. https://www.embeddedts.com/products/TS-CAN1 diff --git a/drivers/net/can/spi/mcp251x.c b/drivers/net/can/spi/mcp251x.c index ec5c64006a16..5a95877b7419 100644 --- a/drivers/net/can/spi/mcp251x.c +++ b/drivers/net/can/spi/mcp251x.c @@ -388,8 +388,8 @@ static void mcp251x_write_2regs(struct spi_device *spi, u8 reg, u8 v1, u8 v2) mcp251x_spi_write(spi, 4); } -static void mcp251x_write_bits(struct spi_device *spi, u8 reg, - u8 mask, u8 val) +static int mcp251x_write_bits(struct spi_device *spi, u8 reg, + u8 mask, u8 val) { struct mcp251x_priv *priv = spi_get_drvdata(spi); @@ -398,7 +398,7 @@ static void mcp251x_write_bits(struct spi_device *spi, u8 reg, priv->spi_tx_buf[2] = mask; priv->spi_tx_buf[3] = val; - mcp251x_spi_write(spi, 4); + return mcp251x_spi_write(spi, 4); } static u8 mcp251x_read_stat(struct spi_device *spi) @@ -441,6 +441,7 @@ static int mcp251x_gpio_request(struct gpio_chip *chip, unsigned int offset) { struct mcp251x_priv *priv = gpiochip_get_data(chip); + int ret; u8 val; /* nothing to be done for inputs */ @@ -450,8 +451,10 @@ static int mcp251x_gpio_request(struct gpio_chip *chip, val = BFPCTRL_BFE(offset - MCP251X_GPIO_RX0BF); mutex_lock(&priv->mcp_lock); - mcp251x_write_bits(priv->spi, BFPCTRL, val, val); + ret = mcp251x_write_bits(priv->spi, BFPCTRL, val, val); mutex_unlock(&priv->mcp_lock); + if (ret) + return ret; priv->reg_bfpctrl |= val; @@ -530,29 +533,35 @@ static int mcp251x_gpio_get_multiple(struct gpio_chip *chip, return 0; } -static void mcp251x_gpio_set(struct gpio_chip *chip, unsigned int offset, - int value) +static int mcp251x_gpio_set(struct gpio_chip *chip, unsigned int offset, + int value) { struct mcp251x_priv *priv = gpiochip_get_data(chip); u8 mask, val; + int ret; mask = BFPCTRL_BFS(offset - MCP251X_GPIO_RX0BF); val = value ? mask : 0; mutex_lock(&priv->mcp_lock); - mcp251x_write_bits(priv->spi, BFPCTRL, mask, val); + ret = mcp251x_write_bits(priv->spi, BFPCTRL, mask, val); mutex_unlock(&priv->mcp_lock); + if (ret) + return ret; priv->reg_bfpctrl &= ~mask; priv->reg_bfpctrl |= val; + + return 0; } -static void +static int mcp251x_gpio_set_multiple(struct gpio_chip *chip, unsigned long *maskp, unsigned long *bitsp) { struct mcp251x_priv *priv = gpiochip_get_data(chip); u8 mask, val; + int ret; mask = FIELD_GET(MCP251X_GPIO_OUTPUT_MASK, maskp[0]); mask = FIELD_PREP(BFPCTRL_BFS_MASK, mask); @@ -561,14 +570,18 @@ mcp251x_gpio_set_multiple(struct gpio_chip *chip, val = FIELD_PREP(BFPCTRL_BFS_MASK, val); if (!mask) - return; + return 0; mutex_lock(&priv->mcp_lock); - mcp251x_write_bits(priv->spi, BFPCTRL, mask, val); + ret = mcp251x_write_bits(priv->spi, BFPCTRL, mask, val); mutex_unlock(&priv->mcp_lock); + if (ret) + return ret; priv->reg_bfpctrl &= ~mask; priv->reg_bfpctrl |= val; + + return 0; } static void mcp251x_gpio_restore(struct spi_device *spi) @@ -594,8 +607,8 @@ static int mcp251x_gpio_setup(struct mcp251x_priv *priv) gpio->get_direction = mcp251x_gpio_get_direction; gpio->get = mcp251x_gpio_get; gpio->get_multiple = mcp251x_gpio_get_multiple; - gpio->set = mcp251x_gpio_set; - gpio->set_multiple = mcp251x_gpio_set_multiple; + gpio->set_rv = mcp251x_gpio_set; + gpio->set_multiple_rv = mcp251x_gpio_set_multiple; gpio->base = -1; gpio->ngpio = ARRAY_SIZE(mcp251x_gpio_names); gpio->names = mcp251x_gpio_names; diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-timestamp.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-timestamp.c index 202ca0d24d03..413a5cb75c13 100644 --- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-timestamp.c +++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-timestamp.c @@ -11,7 +11,7 @@ #include "mcp251xfd.h" -static u64 mcp251xfd_timestamp_raw_read(const struct cyclecounter *cc) +static u64 mcp251xfd_timestamp_raw_read(struct cyclecounter *cc) { const struct mcp251xfd_priv *priv; u32 ts_raw = 0; diff --git a/drivers/net/can/ti_hecc.c b/drivers/net/can/ti_hecc.c index 644e8b8eb91e..e6d6661a908a 100644 --- a/drivers/net/can/ti_hecc.c +++ b/drivers/net/can/ti_hecc.c @@ -383,7 +383,7 @@ static void ti_hecc_start(struct net_device *ndev) * overflows instead of the hardware silently dropping the * messages. */ - mbx_mask = ~BIT(HECC_RX_LAST_MBOX); + mbx_mask = ~BIT_U32(HECC_RX_LAST_MBOX); hecc_write(priv, HECC_CANOPC, mbx_mask); /* Enable interrupts */ diff --git a/drivers/net/can/usb/Kconfig b/drivers/net/can/usb/Kconfig index 9dae0c71a2e1..a7547a83120e 100644 --- a/drivers/net/can/usb/Kconfig +++ b/drivers/net/can/usb/Kconfig @@ -66,6 +66,7 @@ config CAN_GS_USB config CAN_KVASER_USB tristate "Kvaser CAN/USB interface" + select NET_DEVLINK help This driver adds support for Kvaser CAN/USB devices like Kvaser Leaf Light, Kvaser USBcan II and Kvaser Memorator Pro 5xHS. diff --git a/drivers/net/can/usb/etas_es58x/es58x_fd.c b/drivers/net/can/usb/etas_es58x/es58x_fd.c index d924b053677b..6476add1c105 100644 --- a/drivers/net/can/usb/etas_es58x/es58x_fd.c +++ b/drivers/net/can/usb/etas_es58x/es58x_fd.c @@ -429,7 +429,7 @@ static int es58x_fd_enable_channel(struct es58x_priv *priv) es58x_fd_convert_bittiming(&tx_conf_msg.data_bittiming, &priv->can.fd.data_bittiming); - if (can_tdc_is_enabled(&priv->can)) { + if (can_fd_tdc_is_enabled(&priv->can)) { tx_conf_msg.tdc_enabled = 1; tx_conf_msg.tdco = cpu_to_le16(priv->can.fd.tdc.tdco); tx_conf_msg.tdcf = cpu_to_le16(priv->can.fd.tdc.tdcf); diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c index bb6335278e46..c9482d6e947b 100644 --- a/drivers/net/can/usb/gs_usb.c +++ b/drivers/net/can/usb/gs_usb.c @@ -420,7 +420,7 @@ static inline int gs_usb_get_timestamp(const struct gs_usb *parent, return 0; } -static u64 gs_usb_timestamp_read(const struct cyclecounter *cc) __must_hold(&dev->tc_lock) +static u64 gs_usb_timestamp_read(struct cyclecounter *cc) __must_hold(&dev->tc_lock) { struct gs_usb *parent = container_of(cc, struct gs_usb, cc); u32 timestamp = 0; diff --git a/drivers/net/can/usb/kvaser_usb/Makefile b/drivers/net/can/usb/kvaser_usb/Makefile index cf260044f0b9..41b4a11555aa 100644 --- a/drivers/net/can/usb/kvaser_usb/Makefile +++ b/drivers/net/can/usb/kvaser_usb/Makefile @@ -1,3 +1,3 @@ # 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 +kvaser_usb-y = kvaser_usb_core.o kvaser_usb_devlink.o kvaser_usb_leaf.o kvaser_usb_hydra.o diff --git a/drivers/net/can/usb/kvaser_usb/kvaser_usb.h b/drivers/net/can/usb/kvaser_usb/kvaser_usb.h index f6c77eca9f43..46a1b6907a50 100644 --- a/drivers/net/can/usb/kvaser_usb/kvaser_usb.h +++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb.h @@ -27,6 +27,7 @@ #include <linux/spinlock.h> #include <linux/types.h> #include <linux/usb.h> +#include <net/devlink.h> #include <linux/can.h> #include <linux/can/dev.h> @@ -47,6 +48,10 @@ #define KVASER_USB_CAP_EXT_CAP 0x02 #define KVASER_USB_HYDRA_CAP_EXT_CMD 0x04 +#define KVASER_USB_SW_VERSION_MAJOR_MASK GENMASK(31, 24) +#define KVASER_USB_SW_VERSION_MINOR_MASK GENMASK(23, 16) +#define KVASER_USB_SW_VERSION_BUILD_MASK GENMASK(15, 0) + struct kvaser_usb_dev_cfg; enum kvaser_usb_leaf_family { @@ -54,6 +59,11 @@ enum kvaser_usb_leaf_family { KVASER_USBCAN, }; +enum kvaser_usb_led_state { + KVASER_USB_LED_ON = 0, + KVASER_USB_LED_OFF = 1, +}; + #define KVASER_USB_HYDRA_MAX_CMD_LEN 128 struct kvaser_usb_dev_card_data_hydra { u8 channel_to_he[KVASER_USB_MAX_NET_DEVICES]; @@ -78,6 +88,12 @@ struct kvaser_usb_tx_urb_context { u32 echo_index; }; +struct kvaser_usb_fw_version { + u8 major; + u8 minor; + u16 build; +}; + struct kvaser_usb_busparams { __le32 bitrate; u8 tseg1; @@ -96,12 +112,15 @@ struct kvaser_usb { struct usb_endpoint_descriptor *bulk_in, *bulk_out; struct usb_anchor rx_submitted; + u32 ean[2]; + u32 serial_number; + struct kvaser_usb_fw_version fw_version; + u8 hw_revision; + unsigned int nchannels; /* @max_tx_urbs: Firmware-reported maximum number of outstanding, * not yet ACKed, transmissions on this device. This value is * also used as a sentinel for marking free tx contexts. */ - u32 fw_version; - unsigned int nchannels; unsigned int max_tx_urbs; struct kvaser_usb_dev_card_data card_data; @@ -112,6 +131,7 @@ struct kvaser_usb { struct kvaser_usb_net_priv { struct can_priv can; + struct devlink_port devlink_port; struct can_berr_counter bec; /* subdriver-specific data */ @@ -149,6 +169,7 @@ struct kvaser_usb_net_priv { * @dev_get_software_details: get software details * @dev_get_card_info: get card info * @dev_get_capabilities: discover device capabilities + * @dev_set_led: turn on/off device LED * * @dev_set_opt_mode: set ctrlmod * @dev_start_chip: start the CAN controller @@ -176,6 +197,9 @@ struct kvaser_usb_dev_ops { int (*dev_get_software_details)(struct kvaser_usb *dev); int (*dev_get_card_info)(struct kvaser_usb *dev); int (*dev_get_capabilities)(struct kvaser_usb *dev); + int (*dev_set_led)(struct kvaser_usb_net_priv *priv, + enum kvaser_usb_led_state state, + u16 duration_ms); int (*dev_set_opt_mode)(const struct kvaser_usb_net_priv *priv); int (*dev_start_chip)(struct kvaser_usb_net_priv *priv); int (*dev_stop_chip)(struct kvaser_usb_net_priv *priv); @@ -204,6 +228,11 @@ struct kvaser_usb_dev_cfg { extern const struct kvaser_usb_dev_ops kvaser_usb_hydra_dev_ops; extern const struct kvaser_usb_dev_ops kvaser_usb_leaf_dev_ops; +extern const struct devlink_ops kvaser_usb_devlink_ops; + +int kvaser_usb_devlink_port_register(struct kvaser_usb_net_priv *priv); +void kvaser_usb_devlink_port_unregister(struct kvaser_usb_net_priv *priv); + void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv); int kvaser_usb_recv_cmd(const struct kvaser_usb *dev, void *cmd, int len, diff --git a/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c b/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c index daf42080f942..90e77fa0ff4a 100644 --- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c +++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c @@ -364,10 +364,13 @@ resubmit_urb: err = usb_submit_urb(urb, GFP_ATOMIC); if (err == -ENODEV) { for (i = 0; i < dev->nchannels; i++) { - if (!dev->nets[i]) + struct kvaser_usb_net_priv *priv; + + priv = dev->nets[i]; + if (!priv) continue; - netif_device_detach(dev->nets[i]->netdev); + netif_device_detach(priv->netdev); } } else if (err) { dev_err(&dev->intf->dev, @@ -753,6 +756,31 @@ freeurb: return ret; } +static int kvaser_usb_set_phys_id(struct net_device *netdev, + enum ethtool_phys_id_state state) +{ + struct kvaser_usb_net_priv *priv = netdev_priv(netdev); + const struct kvaser_usb_dev_ops *ops = priv->dev->driver_info->ops; + + switch (state) { + case ETHTOOL_ID_ACTIVE: + return 3; /* 3 On/Off cycles per second */ + + case ETHTOOL_ID_ON: + return ops->dev_set_led(priv, KVASER_USB_LED_ON, 1000); + + case ETHTOOL_ID_OFF: + return ops->dev_set_led(priv, KVASER_USB_LED_OFF, 1000); + + case ETHTOOL_ID_INACTIVE: + /* Turn LED off and restore standard function after 1ms */ + return ops->dev_set_led(priv, KVASER_USB_LED_OFF, 1); + + default: + return -EINVAL; + } +} + static const struct net_device_ops kvaser_usb_netdev_ops = { .ndo_open = kvaser_usb_open, .ndo_stop = kvaser_usb_close, @@ -763,30 +791,35 @@ static const struct net_device_ops kvaser_usb_netdev_ops = { static const struct ethtool_ops kvaser_usb_ethtool_ops = { .get_ts_info = can_ethtool_op_get_ts_info_hwts, + .set_phys_id = kvaser_usb_set_phys_id, }; static void kvaser_usb_remove_interfaces(struct kvaser_usb *dev) { const struct kvaser_usb_dev_ops *ops = dev->driver_info->ops; int i; + struct kvaser_usb_net_priv *priv; for (i = 0; i < dev->nchannels; i++) { - if (!dev->nets[i]) + priv = dev->nets[i]; + if (!priv) continue; - unregister_candev(dev->nets[i]->netdev); + unregister_candev(priv->netdev); } kvaser_usb_unlink_all_urbs(dev); for (i = 0; i < dev->nchannels; i++) { - if (!dev->nets[i]) + priv = dev->nets[i]; + if (!priv) continue; if (ops->dev_remove_channel) - ops->dev_remove_channel(dev->nets[i]); + ops->dev_remove_channel(priv); - free_candev(dev->nets[i]->netdev); + kvaser_usb_devlink_port_unregister(priv); + free_candev(priv->netdev); } } @@ -852,26 +885,35 @@ static int kvaser_usb_init_one(struct kvaser_usb *dev, int channel) netdev->ethtool_ops = &kvaser_usb_ethtool_ops; SET_NETDEV_DEV(netdev, &dev->intf->dev); netdev->dev_id = channel; + netdev->dev_port = channel; dev->nets[channel] = priv; if (ops->dev_init_channel) { err = ops->dev_init_channel(priv); if (err) - goto err; + goto candev_free; + } + + err = kvaser_usb_devlink_port_register(priv); + if (err) { + dev_err(&dev->intf->dev, "Failed to register devlink port\n"); + goto candev_free; } err = register_candev(netdev); if (err) { dev_err(&dev->intf->dev, "Failed to register CAN device\n"); - goto err; + goto unregister_devlink_port; } netdev_dbg(netdev, "device registered\n"); return 0; -err: +unregister_devlink_port: + kvaser_usb_devlink_port_unregister(priv); +candev_free: free_candev(netdev); dev->nets[channel] = NULL; return err; @@ -881,6 +923,7 @@ static int kvaser_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct kvaser_usb *dev; + struct devlink *devlink; int err; int i; const struct kvaser_usb_driver_info *driver_info; @@ -890,17 +933,20 @@ static int kvaser_usb_probe(struct usb_interface *intf, if (!driver_info) return -ENODEV; - dev = devm_kzalloc(&intf->dev, sizeof(*dev), GFP_KERNEL); - if (!dev) + devlink = devlink_alloc(&kvaser_usb_devlink_ops, sizeof(*dev), &intf->dev); + if (!devlink) return -ENOMEM; + dev = devlink_priv(devlink); dev->intf = intf; dev->driver_info = driver_info; ops = driver_info->ops; err = ops->dev_setup_endpoints(dev); - if (err) - return dev_err_probe(&intf->dev, err, "Cannot get usb endpoint(s)"); + if (err) { + dev_err_probe(&intf->dev, err, "Cannot get usb endpoint(s)"); + goto free_devlink; + } dev->udev = interface_to_usbdev(intf); @@ -911,55 +957,66 @@ static int kvaser_usb_probe(struct usb_interface *intf, dev->card_data.ctrlmode_supported = 0; dev->card_data.capabilities = 0; err = ops->dev_init_card(dev); - if (err) - return dev_err_probe(&intf->dev, err, - "Failed to initialize card\n"); + if (err) { + dev_err_probe(&intf->dev, err, + "Failed to initialize card\n"); + goto free_devlink; + } err = ops->dev_get_software_info(dev); - if (err) - return dev_err_probe(&intf->dev, err, - "Cannot get software info\n"); + if (err) { + dev_err_probe(&intf->dev, err, + "Cannot get software info\n"); + goto free_devlink; + } if (ops->dev_get_software_details) { err = ops->dev_get_software_details(dev); - if (err) - return dev_err_probe(&intf->dev, err, - "Cannot get software details\n"); + if (err) { + dev_err_probe(&intf->dev, err, + "Cannot get software details\n"); + goto free_devlink; + } } - if (WARN_ON(!dev->cfg)) - return -ENODEV; - - dev_dbg(&intf->dev, "Firmware version: %d.%d.%d\n", - ((dev->fw_version >> 24) & 0xff), - ((dev->fw_version >> 16) & 0xff), - (dev->fw_version & 0xffff)); + if (WARN_ON(!dev->cfg)) { + err = -ENODEV; + goto free_devlink; + } dev_dbg(&intf->dev, "Max outstanding tx = %d URBs\n", dev->max_tx_urbs); err = ops->dev_get_card_info(dev); - if (err) - return dev_err_probe(&intf->dev, err, - "Cannot get card info\n"); + if (err) { + dev_err_probe(&intf->dev, err, + "Cannot get card info\n"); + goto free_devlink; + } if (ops->dev_get_capabilities) { err = ops->dev_get_capabilities(dev); if (err) { - kvaser_usb_remove_interfaces(dev); - return dev_err_probe(&intf->dev, err, - "Cannot get capabilities\n"); + dev_err_probe(&intf->dev, err, + "Cannot get capabilities\n"); + goto remove_interfaces; } } for (i = 0; i < dev->nchannels; i++) { err = kvaser_usb_init_one(dev, i); - if (err) { - kvaser_usb_remove_interfaces(dev); - return err; - } + if (err) + goto remove_interfaces; } + devlink_register(devlink); return 0; + +remove_interfaces: + kvaser_usb_remove_interfaces(dev); +free_devlink: + devlink_free(devlink); + + return err; } static void kvaser_usb_disconnect(struct usb_interface *intf) @@ -972,6 +1029,8 @@ static void kvaser_usb_disconnect(struct usb_interface *intf) return; kvaser_usb_remove_interfaces(dev); + devlink_unregister(priv_to_devlink(dev)); + devlink_free(priv_to_devlink(dev)); } static struct usb_driver kvaser_usb_driver = { diff --git a/drivers/net/can/usb/kvaser_usb/kvaser_usb_devlink.c b/drivers/net/can/usb/kvaser_usb/kvaser_usb_devlink.c new file mode 100644 index 000000000000..e838b82298ae --- /dev/null +++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_devlink.c @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: GPL-2.0 +/* kvaser_usb devlink functions + * + * Copyright (C) 2025 KVASER AB, Sweden. All rights reserved. + */ +#include "kvaser_usb.h" + +#include <linux/netdevice.h> +#include <net/devlink.h> + +#define KVASER_USB_EAN_MSB 0x00073301 + +static int kvaser_usb_devlink_info_get(struct devlink *devlink, + struct devlink_info_req *req, + struct netlink_ext_ack *extack) +{ + struct kvaser_usb *dev = devlink_priv(devlink); + char buf[] = "73301XXXXXXXXXX"; + int ret; + + if (dev->serial_number) { + snprintf(buf, sizeof(buf), "%u", dev->serial_number); + ret = devlink_info_serial_number_put(req, buf); + if (ret) + return ret; + } + + if (dev->fw_version.major) { + snprintf(buf, sizeof(buf), "%u.%u.%u", + dev->fw_version.major, + dev->fw_version.minor, + dev->fw_version.build); + ret = devlink_info_version_running_put(req, + DEVLINK_INFO_VERSION_GENERIC_FW, + buf); + if (ret) + return ret; + } + + if (dev->hw_revision) { + snprintf(buf, sizeof(buf), "%u", dev->hw_revision); + ret = devlink_info_version_fixed_put(req, + DEVLINK_INFO_VERSION_GENERIC_BOARD_REV, + buf); + if (ret) + return ret; + } + + if (dev->ean[1] == KVASER_USB_EAN_MSB) { + snprintf(buf, sizeof(buf), "%x%08x", dev->ean[1], dev->ean[0]); + ret = devlink_info_version_fixed_put(req, + DEVLINK_INFO_VERSION_GENERIC_BOARD_ID, + buf); + if (ret) + return ret; + } + + return 0; +} + +const struct devlink_ops kvaser_usb_devlink_ops = { + .info_get = kvaser_usb_devlink_info_get, +}; + +int kvaser_usb_devlink_port_register(struct kvaser_usb_net_priv *priv) +{ + int ret; + struct devlink_port_attrs attrs = { + .flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL, + .phys.port_number = priv->channel, + }; + devlink_port_attrs_set(&priv->devlink_port, &attrs); + + ret = devlink_port_register(priv_to_devlink(priv->dev), + &priv->devlink_port, priv->channel); + if (ret) + return ret; + + SET_NETDEV_DEVLINK_PORT(priv->netdev, &priv->devlink_port); + + return 0; +} + +void kvaser_usb_devlink_port_unregister(struct kvaser_usb_net_priv *priv) +{ + devlink_port_unregister(&priv->devlink_port); +} diff --git a/drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c b/drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c index 8e88b5917796..a59f20dad692 100644 --- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c +++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c @@ -12,6 +12,7 @@ * distinguish between ERROR_WARNING and ERROR_ACTIVE. */ +#include <linux/bitfield.h> #include <linux/completion.h> #include <linux/device.h> #include <linux/gfp.h> @@ -67,6 +68,8 @@ static const struct kvaser_usb_dev_cfg kvaser_usb_hydra_dev_cfg_rt; #define CMD_SET_BUSPARAMS_RESP 85 #define CMD_GET_CAPABILITIES_REQ 95 #define CMD_GET_CAPABILITIES_RESP 96 +#define CMD_LED_ACTION_REQ 101 +#define CMD_LED_ACTION_RESP 102 #define CMD_RX_MESSAGE 106 #define CMD_MAP_CHANNEL_REQ 200 #define CMD_MAP_CHANNEL_RESP 201 @@ -111,7 +114,7 @@ struct kvaser_cmd_card_info { __le32 clock_res; __le32 mfg_date; __le32 ean[2]; - u8 hw_version; + u8 hw_revision; u8 usb_mode; u8 hw_type; u8 reserved0; @@ -217,6 +220,22 @@ struct kvaser_cmd_get_busparams_res { u8 reserved[20]; } __packed; +/* The device has two LEDs per CAN channel + * The LSB of action field controls the state: + * 0 = ON + * 1 = OFF + * The remaining bits of action field is the LED index + */ +#define KVASER_USB_HYDRA_LED_IDX_MASK GENMASK(31, 1) +#define KVASER_USB_HYDRA_LED_YELLOW_CH0_IDX 3 +#define KVASER_USB_HYDRA_LEDS_PER_CHANNEL 2 +struct kvaser_cmd_led_action_req { + u8 action; + u8 padding; + __le16 duration_ms; + u8 reserved[24]; +} __packed; + /* Ctrl modes */ #define KVASER_USB_HYDRA_CTRLMODE_NORMAL 0x01 #define KVASER_USB_HYDRA_CTRLMODE_LISTEN 0x02 @@ -299,6 +318,8 @@ struct kvaser_cmd { struct kvaser_cmd_get_busparams_req get_busparams_req; struct kvaser_cmd_get_busparams_res get_busparams_res; + struct kvaser_cmd_led_action_req led_action_req; + struct kvaser_cmd_chip_state_event chip_state_event; struct kvaser_cmd_set_ctrlmode set_ctrlmode; @@ -1390,6 +1411,7 @@ static void kvaser_usb_hydra_handle_cmd_std(const struct kvaser_usb *dev, /* Ignored commands */ case CMD_SET_BUSPARAMS_RESP: case CMD_SET_BUSPARAMS_FD_RESP: + case CMD_LED_ACTION_RESP: break; default: @@ -1817,6 +1839,7 @@ static int kvaser_usb_hydra_get_software_details(struct kvaser_usb *dev) size_t cmd_len; int err; u32 flags; + u32 fw_version; struct kvaser_usb_dev_card_data *card_data = &dev->card_data; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); @@ -1841,7 +1864,10 @@ static int kvaser_usb_hydra_get_software_details(struct kvaser_usb *dev) if (err) goto end; - dev->fw_version = le32_to_cpu(cmd->sw_detail_res.sw_version); + fw_version = le32_to_cpu(cmd->sw_detail_res.sw_version); + dev->fw_version.major = FIELD_GET(KVASER_USB_SW_VERSION_MAJOR_MASK, fw_version); + dev->fw_version.minor = FIELD_GET(KVASER_USB_SW_VERSION_MINOR_MASK, fw_version); + dev->fw_version.build = FIELD_GET(KVASER_USB_SW_VERSION_BUILD_MASK, fw_version); flags = le32_to_cpu(cmd->sw_detail_res.sw_flags); if (flags & KVASER_USB_HYDRA_SW_FLAG_FW_BAD) { @@ -1892,6 +1918,10 @@ static int kvaser_usb_hydra_get_card_info(struct kvaser_usb *dev) err = kvaser_usb_hydra_wait_cmd(dev, CMD_GET_CARD_INFO_RESP, &cmd); if (err) return err; + dev->ean[1] = le32_to_cpu(cmd.card_info.ean[1]); + dev->ean[0] = le32_to_cpu(cmd.card_info.ean[0]); + dev->serial_number = le32_to_cpu(cmd.card_info.serial_number); + dev->hw_revision = cmd.card_info.hw_revision; dev->nchannels = cmd.card_info.nchannels; if (dev->nchannels > KVASER_USB_MAX_NET_DEVICES) @@ -1946,6 +1976,36 @@ static int kvaser_usb_hydra_get_capabilities(struct kvaser_usb *dev) return 0; } +static int kvaser_usb_hydra_set_led(struct kvaser_usb_net_priv *priv, + enum kvaser_usb_led_state state, + u16 duration_ms) +{ + struct kvaser_usb *dev = priv->dev; + struct kvaser_cmd *cmd; + size_t cmd_len; + int ret; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + cmd->header.cmd_no = CMD_LED_ACTION_REQ; + cmd_len = kvaser_usb_hydra_cmd_size(cmd); + kvaser_usb_hydra_set_cmd_dest_he(cmd, dev->card_data.hydra.sysdbg_he); + kvaser_usb_hydra_set_cmd_transid(cmd, kvaser_usb_hydra_get_next_transid(dev)); + + cmd->led_action_req.duration_ms = cpu_to_le16(duration_ms); + cmd->led_action_req.action = state | + FIELD_PREP(KVASER_USB_HYDRA_LED_IDX_MASK, + KVASER_USB_HYDRA_LED_YELLOW_CH0_IDX + + KVASER_USB_HYDRA_LEDS_PER_CHANNEL * priv->channel); + + ret = kvaser_usb_send_cmd(dev, cmd, cmd_len); + kfree(cmd); + + return ret; +} + static int kvaser_usb_hydra_set_opt_mode(const struct kvaser_usb_net_priv *priv) { struct kvaser_usb *dev = priv->dev; @@ -2149,6 +2209,7 @@ const struct kvaser_usb_dev_ops kvaser_usb_hydra_dev_ops = { .dev_get_software_details = kvaser_usb_hydra_get_software_details, .dev_get_card_info = kvaser_usb_hydra_get_card_info, .dev_get_capabilities = kvaser_usb_hydra_get_capabilities, + .dev_set_led = kvaser_usb_hydra_set_led, .dev_set_opt_mode = kvaser_usb_hydra_set_opt_mode, .dev_start_chip = kvaser_usb_hydra_start_chip, .dev_stop_chip = kvaser_usb_hydra_stop_chip, diff --git a/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c b/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c index 6a45adcc45bd..c29828a94ad0 100644 --- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c +++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c @@ -10,6 +10,7 @@ * Copyright (C) 2015 Valeo S.A. */ +#include <linux/bitfield.h> #include <linux/completion.h> #include <linux/device.h> #include <linux/gfp.h> @@ -81,6 +82,8 @@ #define CMD_FLUSH_QUEUE_REPLY 68 #define CMD_GET_CAPABILITIES_REQ 95 #define CMD_GET_CAPABILITIES_RESP 96 +#define CMD_LED_ACTION_REQ 101 +#define CMD_LED_ACTION_RESP 102 #define CMD_LEAF_LOG_MESSAGE 106 @@ -135,7 +138,7 @@ struct kvaser_cmd_cardinfo { __le32 padding0; __le32 clock_resolution; __le32 mfgdate; - u8 ean[8]; + __le32 ean[2]; u8 hw_revision; union { struct { @@ -173,6 +176,21 @@ struct kvaser_cmd_busparams { struct kvaser_usb_busparams busparams; } __packed; +/* The device has one LED per CAN channel + * The LSB of action field controls the state: + * 0 = ON + * 1 = OFF + * The remaining bits of action field is the LED index + */ +#define KVASER_USB_LEAF_LED_IDX_MASK GENMASK(31, 1) +#define KVASER_USB_LEAF_LED_YELLOW_CH0_IDX 2 +struct kvaser_cmd_led_action_req { + u8 tid; + u8 action; + __le16 duration_ms; + u8 padding[24]; +} __packed; + struct kvaser_cmd_tx_can { u8 channel; u8 tid; @@ -359,6 +377,8 @@ struct kvaser_cmd { struct kvaser_cmd_cardinfo cardinfo; struct kvaser_cmd_busparams busparams; + struct kvaser_cmd_led_action_req led_action_req; + struct kvaser_cmd_rx_can_header rx_can_header; struct kvaser_cmd_tx_acknowledge_header tx_acknowledge_header; @@ -409,6 +429,7 @@ static const u8 kvaser_usb_leaf_cmd_sizes_leaf[] = { [CMD_ERROR_EVENT] = kvaser_fsize(u.leaf.error_event), /* ignored events: */ [CMD_FLUSH_QUEUE_REPLY] = CMD_SIZE_ANY, + [CMD_LED_ACTION_RESP] = CMD_SIZE_ANY, }; static const u8 kvaser_usb_leaf_cmd_sizes_usbcan[] = { @@ -423,6 +444,8 @@ static const u8 kvaser_usb_leaf_cmd_sizes_usbcan[] = { [CMD_CAN_ERROR_EVENT] = kvaser_fsize(u.usbcan.can_error_event), [CMD_ERROR_EVENT] = kvaser_fsize(u.usbcan.error_event), [CMD_USBCAN_CLOCK_OVERFLOW_EVENT] = kvaser_fsize(u.usbcan.clk_overflow_event), + /* ignored events: */ + [CMD_LED_ACTION_RESP] = CMD_SIZE_ANY, }; /* Summary of a kvaser error event, for a unified Leaf/Usbcan error @@ -718,9 +741,13 @@ static int kvaser_usb_leaf_send_simple_cmd(const struct kvaser_usb *dev, static void kvaser_usb_leaf_get_software_info_leaf(struct kvaser_usb *dev, const struct leaf_cmd_softinfo *softinfo) { + u32 fw_version; u32 sw_options = le32_to_cpu(softinfo->sw_options); - dev->fw_version = le32_to_cpu(softinfo->fw_version); + fw_version = le32_to_cpu(softinfo->fw_version); + dev->fw_version.major = FIELD_GET(KVASER_USB_SW_VERSION_MAJOR_MASK, fw_version); + dev->fw_version.minor = FIELD_GET(KVASER_USB_SW_VERSION_MINOR_MASK, fw_version); + dev->fw_version.build = FIELD_GET(KVASER_USB_SW_VERSION_BUILD_MASK, fw_version); dev->max_tx_urbs = le16_to_cpu(softinfo->max_outstanding_tx); if (sw_options & KVASER_USB_LEAF_SWOPTION_EXT_CAP) @@ -761,6 +788,7 @@ static int kvaser_usb_leaf_get_software_info_inner(struct kvaser_usb *dev) { struct kvaser_cmd cmd; int err; + u32 fw_version; err = kvaser_usb_leaf_send_simple_cmd(dev, CMD_GET_SOFTWARE_INFO, 0); if (err) @@ -775,7 +803,13 @@ static int kvaser_usb_leaf_get_software_info_inner(struct kvaser_usb *dev) kvaser_usb_leaf_get_software_info_leaf(dev, &cmd.u.leaf.softinfo); break; case KVASER_USBCAN: - dev->fw_version = le32_to_cpu(cmd.u.usbcan.softinfo.fw_version); + fw_version = le32_to_cpu(cmd.u.usbcan.softinfo.fw_version); + dev->fw_version.major = FIELD_GET(KVASER_USB_SW_VERSION_MAJOR_MASK, + fw_version); + dev->fw_version.minor = FIELD_GET(KVASER_USB_SW_VERSION_MINOR_MASK, + fw_version); + dev->fw_version.build = FIELD_GET(KVASER_USB_SW_VERSION_BUILD_MASK, + fw_version); dev->max_tx_urbs = le16_to_cpu(cmd.u.usbcan.softinfo.max_outstanding_tx); dev->cfg = &kvaser_usb_leaf_usbcan_dev_cfg; @@ -820,6 +854,10 @@ static int kvaser_usb_leaf_get_card_info(struct kvaser_usb *dev) (dev->driver_info->family == KVASER_USBCAN && dev->nchannels > MAX_USBCAN_NET_DEVICES)) return -EINVAL; + dev->ean[1] = le32_to_cpu(cmd.u.cardinfo.ean[1]); + dev->ean[0] = le32_to_cpu(cmd.u.cardinfo.ean[0]); + dev->serial_number = le32_to_cpu(cmd.u.cardinfo.serial_number); + dev->hw_revision = cmd.u.cardinfo.hw_revision; return 0; } @@ -924,6 +962,34 @@ static int kvaser_usb_leaf_get_capabilities_leaf(struct kvaser_usb *dev) return 0; } +static int kvaser_usb_leaf_set_led(struct kvaser_usb_net_priv *priv, + enum kvaser_usb_led_state state, + u16 duration_ms) +{ + struct kvaser_usb *dev = priv->dev; + struct kvaser_cmd *cmd; + int ret; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + cmd->id = CMD_LED_ACTION_REQ; + cmd->len = CMD_HEADER_LEN + sizeof(struct kvaser_cmd_led_action_req); + cmd->u.led_action_req.tid = 0xff; + + cmd->u.led_action_req.duration_ms = cpu_to_le16(duration_ms); + cmd->u.led_action_req.action = state | + FIELD_PREP(KVASER_USB_LEAF_LED_IDX_MASK, + KVASER_USB_LEAF_LED_YELLOW_CH0_IDX + + priv->channel); + + ret = kvaser_usb_send_cmd(dev, cmd, cmd->len); + kfree(cmd); + + return ret; +} + static int kvaser_usb_leaf_get_capabilities(struct kvaser_usb *dev) { int err = 0; @@ -1638,6 +1704,8 @@ static void kvaser_usb_leaf_handle_command(struct kvaser_usb *dev, if (dev->driver_info->family != KVASER_LEAF) goto warn; break; + case CMD_LED_ACTION_RESP: + break; default: warn: dev_warn(&dev->intf->dev, "Unhandled command (%d)\n", cmd->id); @@ -1927,6 +1995,7 @@ const struct kvaser_usb_dev_ops kvaser_usb_leaf_dev_ops = { .dev_get_software_details = NULL, .dev_get_card_info = kvaser_usb_leaf_get_card_info, .dev_get_capabilities = kvaser_usb_leaf_get_capabilities, + .dev_set_led = kvaser_usb_leaf_set_led, .dev_set_opt_mode = kvaser_usb_leaf_set_opt_mode, .dev_start_chip = kvaser_usb_leaf_start_chip, .dev_stop_chip = kvaser_usb_leaf_stop_chip, diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_fd.c b/drivers/net/can/usb/peak_usb/pcan_usb_fd.c index 4d85b29a17b7..ebefc274b50a 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_fd.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_fd.c @@ -49,7 +49,7 @@ struct __packed pcan_ufd_fw_info { __le32 ser_no; /* S/N */ __le32 flags; /* special functions */ - /* extended data when type == PCAN_USBFD_TYPE_EXT */ + /* extended data when type >= PCAN_USBFD_TYPE_EXT */ u8 cmd_out_ep; /* ep for cmd */ u8 cmd_in_ep; /* ep for replies */ u8 data_out_ep[2]; /* ep for CANx TX */ @@ -982,10 +982,11 @@ static int pcan_usb_fd_init(struct peak_usb_device *dev) dev->can.ctrlmode |= CAN_CTRLMODE_FD_NON_ISO; } - /* if vendor rsp is of type 2, then it contains EP numbers to - * use for cmds pipes. If not, then default EP should be used. + /* if vendor rsp type is greater than or equal to 2, then it + * contains EP numbers to use for cmds pipes. If not, then + * default EP should be used. */ - if (fw_info->type != cpu_to_le16(PCAN_USBFD_TYPE_EXT)) { + if (le16_to_cpu(fw_info->type) < PCAN_USBFD_TYPE_EXT) { fw_info->cmd_out_ep = PCAN_USBPRO_EP_CMDOUT; fw_info->cmd_in_ep = PCAN_USBPRO_EP_CMDIN; } @@ -1018,11 +1019,11 @@ static int pcan_usb_fd_init(struct peak_usb_device *dev) dev->can_channel_id = le32_to_cpu(pdev->usb_if->fw_info.dev_id[dev->ctrl_idx]); - /* if vendor rsp is of type 2, then it contains EP numbers to - * use for data pipes. If not, then statically defined EP are used - * (see peak_usb_create_dev()). + /* if vendor rsp type is greater than or equal to 2, then it contains EP + * numbers to use for data pipes. If not, then statically defined EP are + * used (see peak_usb_create_dev()). */ - if (fw_info->type == cpu_to_le16(PCAN_USBFD_TYPE_EXT)) { + if (le16_to_cpu(fw_info->type) >= PCAN_USBFD_TYPE_EXT) { dev->ep_msg_in = fw_info->data_in_ep; dev->ep_msg_out = fw_info->data_out_ep[dev->ctrl_idx]; } diff --git a/drivers/net/can/xilinx_can.c b/drivers/net/can/xilinx_can.c index 3f2e378199ab..81baec8eb1e5 100644 --- a/drivers/net/can/xilinx_can.c +++ b/drivers/net/can/xilinx_can.c @@ -515,7 +515,7 @@ static int xcan_set_bittiming(struct net_device *ndev) priv->devtype.cantype == XAXI_CANFD_2_0) { /* Setting Baud Rate prescaler value in F_BRPR Register */ btr0 = dbt->brp - 1; - if (can_tdc_is_enabled(&priv->can)) { + if (can_fd_tdc_is_enabled(&priv->can)) { if (priv->devtype.cantype == XAXI_CANFD) btr0 |= FIELD_PREP(XCAN_BRPR_TDCO_MASK, priv->can.fd.tdc.tdco) | XCAN_BRPR_TDC_ENABLE; |