Add LAN78XX OTP_ACCESS flag support

With this flag we can now use ethtool to access OTP:
ethtool --set-priv-flags eth0 OTP_ACCESS on
ethtool -e eth0  # this will read OTP if OTP_ACCESS is on, else EEPROM

When writing to OTP we need to set OTP_ACCESS on and write with the correct magic 0x7873 for OTP
This commit is contained in:
Cutyno 2024-10-24 16:55:24 +02:00 committed by GitHub
parent c2ee9f594d
commit f33fb4f77c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -85,6 +85,7 @@
#define EEPROM_INDICATOR (0xA5)
#define EEPROM_MAC_OFFSET (0x01)
#define MAX_EEPROM_SIZE 512
#define MAX_OTP_SIZE 512
#define OTP_INDICATOR_1 (0xF3)
#define OTP_INDICATOR_2 (0xF7)
@ -172,6 +173,7 @@
#define INT_EP_GPIO_2 (2)
#define INT_EP_GPIO_1 (1)
#define INT_EP_GPIO_0 (0)
#define LAN78XX_NET_FLAG_OTP BIT(0)
static const char lan78xx_gstrings[][ETH_GSTRING_LEN] = {
"RX FCS Errors",
@ -446,6 +448,7 @@ struct lan78xx_net {
unsigned int burst_cap;
unsigned long flags;
u32 priv_flags;
wait_queue_head_t *wait;
unsigned char suspend_count;
@ -1542,6 +1545,10 @@ static void lan78xx_status(struct lan78xx_net *dev, struct urb *urb)
static int lan78xx_ethtool_get_eeprom_len(struct net_device *netdev)
{
struct lan78xx_net *dev = netdev_priv(netdev);
if (dev->priv_flags & LAN78XX_NET_FLAG_OTP)
return MAX_OTP_SIZE;
return MAX_EEPROM_SIZE;
}
@ -1555,8 +1562,9 @@ static int lan78xx_ethtool_get_eeprom(struct net_device *netdev,
if (ret)
return ret;
ee->magic = LAN78XX_EEPROM_MAGIC;
if (dev->priv_flags & LAN78XX_NET_FLAG_OTP)
ret = lan78xx_read_raw_otp(dev, ee->offset, ee->len, data);
else
ret = lan78xx_read_raw_eeprom(dev, ee->offset, ee->len, data);
usb_autopm_put_interface(dev->intf);
@ -1577,30 +1585,39 @@ static int lan78xx_ethtool_set_eeprom(struct net_device *netdev,
/* Invalid EEPROM_INDICATOR at offset zero will result in a failure
* to load data from EEPROM
*/
if (dev->priv_flags & LAN78XX_NET_FLAG_OTP) {
/* Beware! OTP is One Time Programming ONLY! */
if (ee->magic == LAN78XX_OTP_MAGIC)
ret = lan78xx_write_raw_otp(dev, ee->offset, ee->len, data);
} else {
if (ee->magic == LAN78XX_EEPROM_MAGIC)
ret = lan78xx_write_raw_eeprom(dev, ee->offset, ee->len, data);
else if ((ee->magic == LAN78XX_OTP_MAGIC) &&
(ee->offset == 0) &&
(ee->len == 512) &&
(data[0] == OTP_INDICATOR_1))
ret = lan78xx_write_raw_otp(dev, ee->offset, ee->len, data);
}
usb_autopm_put_interface(dev->intf);
return ret;
}
static const char lan78xx_priv_flags_strings[][ETH_GSTRING_LEN] = {
"OTP_ACCESS",
};
static void lan78xx_get_strings(struct net_device *netdev, u32 stringset,
u8 *data)
{
if (stringset == ETH_SS_STATS)
memcpy(data, lan78xx_gstrings, sizeof(lan78xx_gstrings));
else if (stringset == ETH_SS_PRIV_FLAGS)
memcpy(data, lan78xx_priv_flags_strings, sizeof(lan78xx_priv_flags_strings));
}
static int lan78xx_get_sset_count(struct net_device *netdev, int sset)
{
if (sset == ETH_SS_STATS)
return ARRAY_SIZE(lan78xx_gstrings);
else if (sset == ETH_SS_PRIV_FLAGS)
return ARRAY_SIZE(lan78xx_priv_flags_strings);
else
return -EOPNOTSUPP;
}
@ -1617,6 +1634,22 @@ static void lan78xx_get_stats(struct net_device *netdev,
mutex_unlock(&dev->stats.access_lock);
}
static u32 lan78xx_ethtool_get_priv_flags(struct net_device *netdev)
{
struct lan78xx_net *dev = netdev_priv(netdev);
return dev->priv_flags;
}
static int lan78xx_ethtool_set_priv_flags(struct net_device *netdev, u32 flags)
{
struct lan78xx_net *dev = netdev_priv(netdev);
dev->priv_flags = flags;
return 0;
}
static void lan78xx_get_wol(struct net_device *netdev,
struct ethtool_wolinfo *wol)
{
@ -1905,6 +1938,8 @@ static const struct ethtool_ops lan78xx_ethtool_ops = {
.get_eeprom = lan78xx_ethtool_get_eeprom,
.set_eeprom = lan78xx_ethtool_set_eeprom,
.get_ethtool_stats = lan78xx_get_stats,
.get_priv_flags = lan78xx_ethtool_get_priv_flags,
.set_priv_flags = lan78xx_ethtool_set_priv_flags,
.get_sset_count = lan78xx_get_sset_count,
.get_strings = lan78xx_get_strings,
.get_wol = lan78xx_get_wol,