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>
This commit is contained in:
parent
e1bd882252
commit
36d007c6fc
|
@ -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,
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in New Issue