With this flag we can now use ethtool to access the 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 --- drivers/net/usb/lan78xx.c | 55 ++++++++++++++++++++++++++++++++------- 1 file changed, 45 insertions(+), 10 deletions(-) diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c index 8adf77e3557e..2fc9b9b138b0 100644 --- a/drivers/net/usb/lan78xx.c +++ b/drivers/net/usb/lan78xx.c @@ -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,9 +1562,10 @@ static int lan78xx_ethtool_get_eeprom(struct net_device *netdev, if (ret) return ret; - ee->magic = LAN78XX_EEPROM_MAGIC; - - ret = lan78xx_read_raw_eeprom(dev, ee->offset, ee->len, data); + 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 (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); + 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); + } 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, -- 2.43.0