diff options
author | Stephane Grosjean <s.grosjean@peak-system.com> | 2023-01-16 23:09:29 +0300 |
---|---|---|
committer | Marc Kleine-Budde <mkl@pengutronix.de> | 2023-02-02 19:39:23 +0300 |
commit | 36d007c6fc7962cb70ff4b1496d1e24f8b1c1300 (patch) | |
tree | b3e417f2802c691d150703e02e075ee48c49ba39 | |
parent | e1bd882252439dae49c40cfe80997cde5955939f (diff) | |
download | linux-36d007c6fc7962cb70ff4b1496d1e24f8b1c1300.tar.xz |
can: peak_usb: add ethtool interface to user-configurable CAN channel identifier
This patch introduces 3 new functions implementing support for ethtool
access to the CAN channel ID of all USB CAN network interfaces managed by
the driver. With this patch, it is possible to read/write the CAN
channel ID from/to the EEPROM via the ethtool interface.
The CAN channel ID is a user-configurable device identifier that can be
set individually for each CAN interface of a PEAK USB device. Depending on
the device, the identifier has a length of 8 or 32 bit. The identifier
is stored in the non-volatile memory of the device.
The identifier of a CAN interface can be read/written as an 8 or 32 bit
byte string in native (little-endian) byte order, where the length depends
on the device type.
Signed-off-by: Stephane Grosjean <s.grosjean@peak-system.com>
Signed-off-by: Lukas Magel <lukas.magel@posteo.net>
Link: https://lore.kernel.org/all/20230116200932.157769-6-lukas.magel@posteo.net
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
-rw-r--r-- | drivers/net/can/usb/peak_usb/pcan_usb.c | 9 | ||||
-rw-r--r-- | drivers/net/can/usb/peak_usb/pcan_usb_core.c | 80 | ||||
-rw-r--r-- | drivers/net/can/usb/peak_usb/pcan_usb_core.h | 6 | ||||
-rw-r--r-- | drivers/net/can/usb/peak_usb/pcan_usb_fd.c | 3 | ||||
-rw-r--r-- | drivers/net/can/usb/peak_usb/pcan_usb_pro.c | 3 |
5 files changed, 101 insertions, 0 deletions
diff --git a/drivers/net/can/usb/peak_usb/pcan_usb.c b/drivers/net/can/usb/peak_usb/pcan_usb.c index 44e894a1f2c2..bead4f4ba472 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb.c @@ -982,9 +982,18 @@ static int pcan_usb_set_phys_id(struct net_device *netdev, return err; } +/* This device only handles 8-bit CAN channel id. */ +static int pcan_usb_get_eeprom_len(struct net_device *netdev) +{ + return sizeof(u8); +} + static const struct ethtool_ops pcan_usb_ethtool_ops = { .set_phys_id = pcan_usb_set_phys_id, .get_ts_info = pcan_get_ts_info, + .get_eeprom_len = pcan_usb_get_eeprom_len, + .get_eeprom = peak_usb_get_eeprom, + .set_eeprom = peak_usb_set_eeprom, }; /* diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.c b/drivers/net/can/usb/peak_usb/pcan_usb_core.c index 3a73eac314ff..3bfd27742ae4 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_core.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.c @@ -808,6 +808,86 @@ static const struct net_device_ops peak_usb_netdev_ops = { .ndo_change_mtu = can_change_mtu, }; +/* CAN-USB devices generally handle 32-bit CAN channel IDs. + * In case one doesn't, then it have to overload this function. + */ +int peak_usb_get_eeprom_len(struct net_device *netdev) +{ + return sizeof(u32); +} + +/* Every CAN-USB device exports the dev_get_can_channel_id() operation. It is used + * here to fill the data buffer with the user defined CAN channel ID. + */ +int peak_usb_get_eeprom(struct net_device *netdev, + struct ethtool_eeprom *eeprom, u8 *data) +{ + struct peak_usb_device *dev = netdev_priv(netdev); + u32 ch_id; + __le32 ch_id_le; + int err; + + err = dev->adapter->dev_get_can_channel_id(dev, &ch_id); + if (err) + return err; + + /* ethtool operates on individual bytes. The byte order of the CAN + * channel id in memory depends on the kernel architecture. We + * convert the CAN channel id back to the native byte order of the PEAK + * device itself to ensure that the order is consistent for all + * host architectures. + */ + ch_id_le = cpu_to_le32(ch_id); + memcpy(data, (u8 *)&ch_id_le + eeprom->offset, eeprom->len); + + /* update cached value */ + dev->can_channel_id = ch_id; + return err; +} + +/* Every CAN-USB device exports the dev_get_can_channel_id()/dev_set_can_channel_id() + * operations. They are used here to set the new user defined CAN channel ID. + */ +int peak_usb_set_eeprom(struct net_device *netdev, + struct ethtool_eeprom *eeprom, u8 *data) +{ + struct peak_usb_device *dev = netdev_priv(netdev); + u32 ch_id; + __le32 ch_id_le; + int err; + + /* first, read the current user defined CAN channel ID */ + err = dev->adapter->dev_get_can_channel_id(dev, &ch_id); + if (err) { + netdev_err(netdev, "Failed to init CAN channel id (err %d)\n", err); + return err; + } + + /* do update the value with user given bytes. + * ethtool operates on individual bytes. The byte order of the CAN + * channel ID in memory depends on the kernel architecture. We + * convert the CAN channel ID back to the native byte order of the PEAK + * device itself to ensure that the order is consistent for all + * host architectures. + */ + ch_id_le = cpu_to_le32(ch_id); + memcpy((u8 *)&ch_id_le + eeprom->offset, data, eeprom->len); + ch_id = le32_to_cpu(ch_id_le); + + /* flash the new value now */ + err = dev->adapter->dev_set_can_channel_id(dev, ch_id); + if (err) { + netdev_err(netdev, "Failed to write new CAN channel id (err %d)\n", + err); + return err; + } + + /* update cached value with the new one */ + dev->can_channel_id = ch_id; + + return 0; +} + int pcan_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info) { info->so_timestamping = diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.h b/drivers/net/can/usb/peak_usb/pcan_usb_core.h index 1e461aef0f2a..980e315186cf 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_core.h +++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.h @@ -149,4 +149,10 @@ void peak_usb_async_complete(struct urb *urb); void peak_usb_restart_complete(struct peak_usb_device *dev); int pcan_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info); +/* common 32-bit CAN channel ID ethtool management */ +int peak_usb_get_eeprom_len(struct net_device *netdev); +int peak_usb_get_eeprom(struct net_device *netdev, + struct ethtool_eeprom *eeprom, u8 *data); +int peak_usb_set_eeprom(struct net_device *netdev, + struct ethtool_eeprom *eeprom, u8 *data); #endif 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 1ea4cfdfd640..fd925ae96331 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_fd.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_fd.c @@ -1124,6 +1124,9 @@ static int pcan_usb_fd_set_phys_id(struct net_device *netdev, static const struct ethtool_ops pcan_usb_fd_ethtool_ops = { .set_phys_id = pcan_usb_fd_set_phys_id, .get_ts_info = pcan_get_ts_info, + .get_eeprom_len = peak_usb_get_eeprom_len, + .get_eeprom = peak_usb_get_eeprom, + .set_eeprom = peak_usb_set_eeprom, }; /* describes the PCAN-USB FD adapter */ diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c index 061f04c20f96..0c805d9672bf 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c @@ -1037,6 +1037,9 @@ static int pcan_usb_pro_set_phys_id(struct net_device *netdev, static const struct ethtool_ops pcan_usb_pro_ethtool_ops = { .set_phys_id = pcan_usb_pro_set_phys_id, .get_ts_info = pcan_get_ts_info, + .get_eeprom_len = peak_usb_get_eeprom_len, + .get_eeprom = peak_usb_get_eeprom, + .set_eeprom = peak_usb_set_eeprom, }; /* |