Currently ethtool implementation does not have a way to pass the metadata
for eeprom related operations. Some adapters have a complicated
non-volatile memory implementation that requires additional information –
there are drivers [bnx2x and bnxt] that use the ‘magic’ field in the
{G,S}EEPROM  for that purpose, although that’s not its intended usage.

This patch adds a provision to pass the eeprom metadata for
%ETHTOOL_SEEPROM/%ETHTOOL_GEEPROM implementations. User provided metadata
will be cached by the driver and assigns a magic value which the
application need to use for the subsequent {G,S}EEPROM command.
---
 include/linux/ethtool.h      |  1 +
 include/uapi/linux/ethtool.h | 29 +++++++++++++++++++++++++++++
 net/core/ethtool.c           | 25 +++++++++++++++++++++++++
 3 files changed, 55 insertions(+)

diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index 9ded8c6..6f98c2a 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -316,6 +316,7 @@ struct ethtool_ops {
                              struct ethtool_eeprom *, u8 *);
        int     (*set_eeprom)(struct net_device *,
                              struct ethtool_eeprom *, u8 *);
+       int     (*set_meeprom)(struct net_device *, struct ethtool_meeprom *);
        int     (*get_coalesce)(struct net_device *, struct ethtool_coalesce *);
        int     (*set_coalesce)(struct net_device *, struct ethtool_coalesce *);
        void    (*get_ringparam)(struct net_device *,
diff --git a/include/uapi/linux/ethtool.h b/include/uapi/linux/ethtool.h
index 9222db8..f0f28a8 100644
--- a/include/uapi/linux/ethtool.h
+++ b/include/uapi/linux/ethtool.h
@@ -279,6 +279,13 @@ struct ethtool_regs {
  *     The value passed in to %ETHTOOL_SEEPROM must match the value
  *     returned by %ETHTOOL_GEEPROM for the same device.  This is
  *     unused when @cmd is %ETHTOOL_GMODULEEEPROM.
+ *     Depending on @cmd, the value passed must match:
+ *     - For %ETHTOOL_GMODULEEEPROM, no requirements.
+ *     - For %ETHTOOL_GEEPROM, must match the value returned by the
+ *             previous %ETHTOOL_SEEPROMMETA in case device supports it.
+ *     - For %ETHTOOL_SEEPROM, must match value returned by the previous
+ *             %ETHTOOL_SEEPROMMETA in case device supports it, or by
+ *             previous %ETHTOOL_GEEPROM otherwise.
  * @offset: Offset within the EEPROM to begin reading/writing, in bytes
  * @len: On entry, number of bytes to read/write.  On successful
  *     return, number of bytes actually read/written.  In case of
@@ -298,6 +305,27 @@ struct ethtool_eeprom {
 };
 
 /**
+ * struct ethtool_meeprom - Set EEPROM metadata
+ * @cmd: Command number = %ETHTOOL_SEEPROMMETA
+ * @metadata: eeprom metadata corresponds to the successive %ETHTOOL_SEEPROM or
+ *     %ETHTOOL_GEEPROM command.
+ * @magic: A 'magic cookie' value to be used by the successive 
%ETHTOOL_SEEPROM/
+ *     %ETHTOOL_GEEPROM command. User provided eeprom metadata will be
+ *     assoicated with a magic value. The value passed in to %ETHTOOL_SEEPROM
+ *     or %ETHTOOL_GEEPROM must match with the value returned by
+ *     %ETHTOOL_SEEPROMMETA for the same device.
+ *     Essentialy user will send eeprom meta data, followed by %ETHTOOL_SEEPROM
+ *     or %ETHTOOL_GEEPROM command. It's driver's responsibility to map the
+ *     metadata to the subsequent eeprom command, using the magic to validate
+ *     correctness.
+ */
+struct ethtool_meeprom {
+       __u32 cmd;
+       __u32 metadata;
+       __u32 magic;
+};
+
+/**
  * struct ethtool_eee - Energy Efficient Ethernet information
  * @cmd: ETHTOOL_{G,S}EEE
  * @supported: Mask of %SUPPORTED_* flags for the speed/duplex combinations
@@ -1315,6 +1343,7 @@ struct ethtool_per_queue_op {
 #define ETHTOOL_GLINKSETTINGS  0x0000004c /* Get ethtool_link_settings */
 #define ETHTOOL_SLINKSETTINGS  0x0000004d /* Set ethtool_link_settings */
 
+#define ETHTOOL_SEEPROMMETA    0x0000004e /* Set eeprom metadata */
 
 /* compatibility with older code */
 #define SPARC_ETH_GSET         ETHTOOL_GSET
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index bdb4013..c5efadd 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -2421,6 +2421,28 @@ static int ethtool_set_per_queue(struct net_device *dev, 
void __user *useraddr)
        };
 }
 
+static int ethtool_set_meeprom(struct net_device *dev, void __user *useraddr)
+{
+       const struct ethtool_ops *ops = dev->ethtool_ops;
+       struct ethtool_meeprom meeprom;
+       int ret;
+
+       if (!ops->set_meeprom)
+               return -EOPNOTSUPP;
+
+       if (copy_from_user(&meeprom, useraddr, sizeof(meeprom)))
+               return -EFAULT;
+
+       ret = ops->set_meeprom(dev, &meeprom);
+       if (ret)
+               return ret;
+
+       if (copy_to_user(useraddr, &meeprom, sizeof(meeprom)))
+               return -EFAULT;
+
+       return 0;
+}
+
 /* The main entry point in this file.  Called from net/core/dev_ioctl.c */
 
 int dev_ethtool(struct net *net, struct ifreq *ifr)
@@ -2683,6 +2705,9 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
        case ETHTOOL_SLINKSETTINGS:
                rc = ethtool_set_link_ksettings(dev, useraddr);
                break;
+       case ETHTOOL_SEEPROMMETA:
+               rc = ethtool_set_meeprom(dev, useraddr);
+               break;
        default:
                rc = -EOPNOTSUPP;
        }
-- 
1.8.3.1

Reply via email to