mirror of
https://github.com/torvalds/linux.git
synced 2026-05-30 01:53:29 +02:00
Merge patch series "can: kvaser_pciefd: Simplify identification of physical CAN interfaces"
Jimmy Assarsson <extja@kvaser.com> says: This patch series simplifies the process of identifying which network interface (can0..canX) corresponds to which physical CAN channel on Kvaser PCIe based CAN interfaces. Changes in v4: - Fix transient Sparse warning - Add tag Reviewed-by Vincent Mailhol Changes in v3: - Fixed typo; kvaser_pcied -> kvaser_pciefd in documentation patch Changes in v2: - Replace use of netdev.dev_id with netdev.dev_port - Formatting and refactoring - New patch with devlink documentation Link: https://patch.msgid.link/20250725123230.8-1-extja@kvaser.com Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
This commit is contained in:
commit
46647a8405
|
|
@ -85,6 +85,7 @@ parameters, info versions, and other features it supports.
|
|||
ionic
|
||||
ice
|
||||
ixgbe
|
||||
kvaser_pciefd
|
||||
mlx4
|
||||
mlx5
|
||||
mlxsw
|
||||
|
|
|
|||
24
Documentation/networking/devlink/kvaser_pciefd.rst
Normal file
24
Documentation/networking/devlink/kvaser_pciefd.rst
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
=============================
|
||||
kvaser_pciefd devlink support
|
||||
=============================
|
||||
|
||||
This document describes the devlink features implemented by the
|
||||
``kvaser_pciefd`` device driver.
|
||||
|
||||
Info versions
|
||||
=============
|
||||
|
||||
The ``kvaser_pciefd`` driver reports the following versions
|
||||
|
||||
.. list-table:: devlink info versions implemented
|
||||
:widths: 5 5 90
|
||||
|
||||
* - Name
|
||||
- Type
|
||||
- Description
|
||||
* - ``fw``
|
||||
- running
|
||||
- Version of the firmware running on the device. Also available
|
||||
through ``ethtool -i`` as ``firmware-version``.
|
||||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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/
|
||||
|
|
|
|||
3
drivers/net/can/kvaser_pciefd/Makefile
Normal file
3
drivers/net/can/kvaser_pciefd/Makefile
Normal file
|
|
@ -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
|
||||
96
drivers/net/can/kvaser_pciefd/kvaser_pciefd.h
Normal file
96
drivers/net/can/kvaser_pciefd/kvaser_pciefd.h
Normal file
|
|
@ -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 */
|
||||
|
|
@ -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 @@ static int kvaser_pciefd_probe(struct pci_dev *pdev,
|
|||
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 = {
|
||||
60
drivers/net/can/kvaser_pciefd/kvaser_pciefd_devlink.c
Normal file
60
drivers/net/can/kvaser_pciefd/kvaser_pciefd_devlink.c
Normal file
|
|
@ -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);
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user