nfp: nsp: implement read SFF module EEPROM
authorDirk van der Merwe <dirk.vandermerwe@netronome.com>
Sat, 30 Mar 2019 02:24:42 +0000 (19:24 -0700)
committerDavid S. Miller <davem@davemloft.net>
Tue, 2 Apr 2019 01:05:13 +0000 (18:05 -0700)
The NSP now provides the ability to read from the SFF module EEPROM.
Note that even if an error occurs, the NSP may still provide some of the
data.

Signed-off-by: Dirk van der Merwe <dirk.vandermerwe@netronome.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c
drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h

index 3a4e224a64b71745284bd1016951438ca916ecf1..42cf4fd875eacf34a4e287180b63a57192a1ea48 100644 (file)
@@ -79,6 +79,8 @@
 #define NFP_VERSIONS_NCSI_OFF  22
 #define NFP_VERSIONS_CFGR_OFF  26
 
+#define NSP_SFF_EEPROM_BLOCK_LEN       8
+
 enum nfp_nsp_cmd {
        SPCODE_NOOP             = 0, /* No operation */
        SPCODE_SOFT_RESET       = 1, /* Soft reset the NFP */
@@ -95,6 +97,7 @@ enum nfp_nsp_cmd {
        SPCODE_FW_STORED        = 16, /* If no FW loaded, load flash app FW */
        SPCODE_HWINFO_LOOKUP    = 17, /* Lookup HWinfo with overwrites etc. */
        SPCODE_VERSIONS         = 21, /* Report FW versions */
+       SPCODE_READ_SFF_EEPROM  = 22, /* Read module EEPROM */
 };
 
 struct nfp_nsp_dma_buf {
@@ -965,3 +968,62 @@ const char *nfp_nsp_versions_get(enum nfp_nsp_versions id, bool flash,
 
        return (const char *)&buf[buf_off];
 }
+
+static int
+__nfp_nsp_module_eeprom(struct nfp_nsp *state, void *buf, unsigned int size)
+{
+       struct nfp_nsp_command_buf_arg module_eeprom = {
+               {
+                       .code           = SPCODE_READ_SFF_EEPROM,
+                       .option         = size,
+               },
+               .in_buf         = buf,
+               .in_size        = size,
+               .out_buf        = buf,
+               .out_size       = size,
+       };
+
+       return nfp_nsp_command_buf(state, &module_eeprom);
+}
+
+int nfp_nsp_read_module_eeprom(struct nfp_nsp *state, int eth_index,
+                              unsigned int offset, void *data,
+                              unsigned int len, unsigned int *read_len)
+{
+       struct eeprom_buf {
+               u8 metalen;
+               __le16 length;
+               __le16 offset;
+               __le16 readlen;
+               u8 eth_index;
+               u8 data[0];
+       } __packed *buf;
+       int bufsz, ret;
+
+       BUILD_BUG_ON(offsetof(struct eeprom_buf, data) % 8);
+
+       /* Buffer must be large enough and rounded to the next block size. */
+       bufsz = struct_size(buf, data, round_up(len, NSP_SFF_EEPROM_BLOCK_LEN));
+       buf = kzalloc(bufsz, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       buf->metalen =
+               offsetof(struct eeprom_buf, data) / NSP_SFF_EEPROM_BLOCK_LEN;
+       buf->length = cpu_to_le16(len);
+       buf->offset = cpu_to_le16(offset);
+       buf->eth_index = eth_index;
+
+       ret = __nfp_nsp_module_eeprom(state, buf, bufsz);
+
+       *read_len = min_t(unsigned int, len, le16_to_cpu(buf->readlen));
+       if (*read_len)
+               memcpy(data, buf->data, *read_len);
+
+       if (!ret && *read_len < len)
+               ret = -EIO;
+
+       kfree(buf);
+
+       return ret;
+}
index bd9c358c646fde11ae590d758a8e23b9b43eda52..22ee6985ee1c31408b55e2375e1e4197b70c912e 100644 (file)
@@ -22,6 +22,9 @@ int nfp_nsp_write_flash(struct nfp_nsp *state, const struct firmware *fw);
 int nfp_nsp_mac_reinit(struct nfp_nsp *state);
 int nfp_nsp_load_stored_fw(struct nfp_nsp *state);
 int nfp_nsp_hwinfo_lookup(struct nfp_nsp *state, void *buf, unsigned int size);
+int nfp_nsp_read_module_eeprom(struct nfp_nsp *state, int eth_index,
+                              unsigned int offset, void *data,
+                              unsigned int len, unsigned int *read_len);
 
 static inline bool nfp_nsp_has_mac_reinit(struct nfp_nsp *state)
 {
@@ -43,6 +46,11 @@ static inline bool nfp_nsp_has_versions(struct nfp_nsp *state)
        return nfp_nsp_get_abi_ver_minor(state) > 27;
 }
 
+static inline bool nfp_nsp_has_read_module_eeprom(struct nfp_nsp *state)
+{
+       return nfp_nsp_get_abi_ver_minor(state) > 28;
+}
+
 enum nfp_eth_interface {
        NFP_INTERFACE_NONE      = 0,
        NFP_INTERFACE_SFP       = 1,