Re: [PATCH net-next] sfc: Add ethtool -m support for QSFP modules

2017-07-19 Thread David Miller
From: Martin Habets 
Date: Tue, 18 Jul 2017 16:43:19 +0100

> This also adds support for non-QSFP modules attached to QSFP.
> 
> Signed-off-by: Martin Habets 

Applied, thanks!


[PATCH net-next] sfc: Add ethtool -m support for QSFP modules

2017-07-18 Thread Martin Habets
This also adds support for non-QSFP modules attached to QSFP.

Signed-off-by: Martin Habets 
---
 drivers/net/ethernet/sfc/mcdi_port.c |  224 +++---
 1 file changed, 181 insertions(+), 43 deletions(-)

diff --git a/drivers/net/ethernet/sfc/mcdi_port.c 
b/drivers/net/ethernet/sfc/mcdi_port.c
index c905971c5f3a..d3f96a8f743b 100644
--- a/drivers/net/ethernet/sfc/mcdi_port.c
+++ b/drivers/net/ethernet/sfc/mcdi_port.c
@@ -746,59 +746,171 @@ static const char *efx_mcdi_phy_test_name(struct efx_nic 
*efx,
return NULL;
 }
 
-#define SFP_PAGE_SIZE  128
-#define SFP_NUM_PAGES  2
-static int efx_mcdi_phy_get_module_eeprom(struct efx_nic *efx,
- struct ethtool_eeprom *ee, u8 *data)
+#define SFP_PAGE_SIZE  128
+#define SFF_DIAG_TYPE_OFFSET   92
+#define SFF_DIAG_ADDR_CHANGE   BIT(2)
+#define SFF_8079_NUM_PAGES 2
+#define SFF_8472_NUM_PAGES 4
+#define SFF_8436_NUM_PAGES 5
+#define SFF_DMT_LEVEL_OFFSET   94
+
+/** efx_mcdi_phy_get_module_eeprom_page() - Get a single page of module eeprom
+ * @efx:   NIC context
+ * @page:  EEPROM page number
+ * @data:  Destination data pointer
+ * @offset:Offset in page to copy from in to data
+ * @space: Space available in data
+ *
+ * Return:
+ *   >=0 - amount of data copied
+ *   <0  - error
+ */
+static int efx_mcdi_phy_get_module_eeprom_page(struct efx_nic *efx,
+  unsigned int page,
+  u8 *data, ssize_t offset,
+  ssize_t space)
 {
MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_PHY_MEDIA_INFO_OUT_LENMAX);
MCDI_DECLARE_BUF(inbuf, MC_CMD_GET_PHY_MEDIA_INFO_IN_LEN);
size_t outlen;
-   int rc;
unsigned int payload_len;
-   unsigned int space_remaining = ee->len;
-   unsigned int page;
-   unsigned int page_off;
unsigned int to_copy;
-   u8 *user_data = data;
+   int rc;
 
-   BUILD_BUG_ON(SFP_PAGE_SIZE * SFP_NUM_PAGES != ETH_MODULE_SFF_8079_LEN);
+   if (offset > SFP_PAGE_SIZE)
+   return -EINVAL;
 
-   page_off = ee->offset % SFP_PAGE_SIZE;
-   page = ee->offset / SFP_PAGE_SIZE;
+   to_copy = min(space, SFP_PAGE_SIZE - offset);
 
-   while (space_remaining && (page < SFP_NUM_PAGES)) {
-   MCDI_SET_DWORD(inbuf, GET_PHY_MEDIA_INFO_IN_PAGE, page);
+   MCDI_SET_DWORD(inbuf, GET_PHY_MEDIA_INFO_IN_PAGE, page);
+   rc = efx_mcdi_rpc_quiet(efx, MC_CMD_GET_PHY_MEDIA_INFO,
+   inbuf, sizeof(inbuf),
+   outbuf, sizeof(outbuf),
+   );
 
-   rc = efx_mcdi_rpc(efx, MC_CMD_GET_PHY_MEDIA_INFO,
- inbuf, sizeof(inbuf),
- outbuf, sizeof(outbuf),
- );
-   if (rc)
-   return rc;
+   if (rc)
+   return rc;
+
+   if (outlen < (MC_CMD_GET_PHY_MEDIA_INFO_OUT_DATA_OFST +
+   SFP_PAGE_SIZE))
+   return -EIO;
+
+   payload_len = MCDI_DWORD(outbuf, GET_PHY_MEDIA_INFO_OUT_DATALEN);
+   if (payload_len != SFP_PAGE_SIZE)
+   return -EIO;
 
-   if (outlen < (MC_CMD_GET_PHY_MEDIA_INFO_OUT_DATA_OFST +
- SFP_PAGE_SIZE))
-   return -EIO;
+   memcpy(data, MCDI_PTR(outbuf, GET_PHY_MEDIA_INFO_OUT_DATA) + offset,
+  to_copy);
 
-   payload_len = MCDI_DWORD(outbuf,
-GET_PHY_MEDIA_INFO_OUT_DATALEN);
-   if (payload_len != SFP_PAGE_SIZE)
-   return -EIO;
+   return to_copy;
+}
 
-   /* Copy as much as we can into data */
-   payload_len -= page_off;
-   to_copy = (space_remaining < payload_len) ?
-   space_remaining : payload_len;
+static int efx_mcdi_phy_get_module_eeprom_byte(struct efx_nic *efx,
+  unsigned int page,
+  u8 byte)
+{
+   int rc;
+   u8 data;
 
-   memcpy(user_data,
-  MCDI_PTR(outbuf, GET_PHY_MEDIA_INFO_OUT_DATA) + page_off,
-  to_copy);
+   rc = efx_mcdi_phy_get_module_eeprom_page(efx, page, , byte, 1);
+   if (rc == 1)
+   return data;
+
+   return rc;
+}
+
+static int efx_mcdi_phy_diag_type(struct efx_nic *efx)
+{
+   /* Page zero of the EEPROM includes the diagnostic type at byte 92. */
+   return efx_mcdi_phy_get_module_eeprom_byte(efx, 0,
+  SFF_DIAG_TYPE_OFFSET);
+}
 
-   space_remaining -= to_copy;
-   user_data += to_copy;
-   page_off = 0;
-