Author: arybchik
Date: Wed Feb 10 12:14:56 2016
New Revision: 295467
URL: https://svnweb.freebsd.org/changeset/base/295467

Log:
  sfxge: implement SIOCGI2C to read information from phy modules
  
  The IOCTL is used by 'ifconfig -v' to show SFP+/QSFP+ information
  including inventory information and dianostics (temperature, light
  levels, voltage etc).
  
  Reviewed by:    gnn,melifaro
  Sponsored by:   Solarflare Communications, Inc.
  MFC after:      2 days
  Differential Revision: https://reviews.freebsd.org/D5240

Modified:
  head/sys/dev/sfxge/common/efx.h
  head/sys/dev/sfxge/common/efx_mcdi.c
  head/sys/dev/sfxge/common/efx_mcdi.h
  head/sys/dev/sfxge/common/efx_phy.c
  head/sys/dev/sfxge/sfxge.c

Modified: head/sys/dev/sfxge/common/efx.h
==============================================================================
--- head/sys/dev/sfxge/common/efx.h     Wed Feb 10 10:28:33 2016        
(r295466)
+++ head/sys/dev/sfxge/common/efx.h     Wed Feb 10 12:14:56 2016        
(r295467)
@@ -879,6 +879,14 @@ efx_phy_media_type_get(
        __in            efx_nic_t *enp,
        __out           efx_phy_media_type_t *typep);
 
+extern                                 efx_rc_t
+efx_phy_module_get_info(
+       __in                            efx_nic_t *enp,
+       __in                            uint8_t dev_addr,
+       __in                            uint8_t offset,
+       __in                            uint8_t len,
+       __out_bcount(len)               uint8_t *data);
+
 #if EFSYS_OPT_PHY_STATS
 
 /* START MKCONFIG GENERATED PhyHeaderStatsBlock 30ed56ad501f8e36 */

Modified: head/sys/dev/sfxge/common/efx_mcdi.c
==============================================================================
--- head/sys/dev/sfxge/common/efx_mcdi.c        Wed Feb 10 10:28:33 2016        
(r295466)
+++ head/sys/dev/sfxge/common/efx_mcdi.c        Wed Feb 10 12:14:56 2016        
(r295467)
@@ -2078,5 +2078,217 @@ fail1:
        return (rc);
 }
 
+/*
+ * Size of media information page in accordance with SFF-8472 and SFF-8436.
+ * It is used in MCDI interface as well.
+ */
+#define        EFX_PHY_MEDIA_INFO_PAGE_SIZE            0x80
+
+static __checkReturn           efx_rc_t
+efx_mcdi_get_phy_media_info(
+       __in                    efx_nic_t *enp,
+       __in                    uint32_t mcdi_page,
+       __in                    uint8_t offset,
+       __in                    uint8_t len,
+       __out_bcount(len)       uint8_t *data)
+{
+       efx_mcdi_req_t req;
+       uint8_t payload[MAX(MC_CMD_GET_PHY_MEDIA_INFO_IN_LEN,
+                           MC_CMD_GET_PHY_MEDIA_INFO_OUT_LEN(
+                               EFX_PHY_MEDIA_INFO_PAGE_SIZE))];
+       efx_rc_t rc;
+
+       EFSYS_ASSERT((uint32_t)offset + len <= EFX_PHY_MEDIA_INFO_PAGE_SIZE);
+
+       (void) memset(payload, 0, sizeof (payload));
+       req.emr_cmd = MC_CMD_GET_PHY_MEDIA_INFO;
+       req.emr_in_buf = payload;
+       req.emr_in_length = MC_CMD_GET_PHY_MEDIA_INFO_IN_LEN;
+       req.emr_out_buf = payload;
+       req.emr_out_length =
+           MC_CMD_GET_PHY_MEDIA_INFO_OUT_LEN(EFX_PHY_MEDIA_INFO_PAGE_SIZE);
+
+       MCDI_IN_SET_DWORD(req, GET_PHY_MEDIA_INFO_IN_PAGE, mcdi_page);
+
+       efx_mcdi_execute(enp, &req);
+
+       if (req.emr_rc != 0) {
+               rc = req.emr_rc;
+               goto fail1;
+       }
+
+       if (req.emr_out_length_used !=
+           MC_CMD_GET_PHY_MEDIA_INFO_OUT_LEN(EFX_PHY_MEDIA_INFO_PAGE_SIZE)) {
+               rc = EMSGSIZE;
+               goto fail2;
+       }
+
+       if (MCDI_OUT_DWORD(req, GET_PHY_MEDIA_INFO_OUT_DATALEN) !=
+           EFX_PHY_MEDIA_INFO_PAGE_SIZE) {
+               rc = EIO;
+               goto fail3;
+       }
+
+       memcpy(data,
+           MCDI_OUT2(req, uint8_t, GET_PHY_MEDIA_INFO_OUT_DATA) + offset,
+           len);
+
+       return (0);
+
+fail3:
+       EFSYS_PROBE(fail3);
+fail2:
+       EFSYS_PROBE(fail2);
+fail1:
+       EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+       return (rc);
+}
+
+/*
+ * 2-wire device address of the base information in accordance with SFF-8472
+ * Diagnostic Monitoring Interface for Optical Transceivers section
+ * 4 Memory Organization.
+ */
+#define        EFX_PHY_MEDIA_INFO_DEV_ADDR_SFP_BASE    0xA0
+
+/*
+ * 2-wire device address of the digital diagnostics monitoring interface
+ * in accordance with SFF-8472 Diagnostic Monitoring Interface for Optical
+ * Transceivers section 4 Memory Organization.
+ */
+#define        EFX_PHY_MEDIA_INFO_DEV_ADDR_SFP_DDM     0xA2
+
+/*
+ * Hard wired 2-wire device address for QSFP+ in accordance with SFF-8436
+ * QSFP+ 10 Gbs 4X PLUGGABLE TRANSCEIVER section 7.4 Device Addressing and
+ * Operation.
+ */
+#define        EFX_PHY_MEDIA_INFO_DEV_ADDR_QSFP        0xA0
+
+       __checkReturn           efx_rc_t
+efx_mcdi_phy_module_get_info(
+       __in                    efx_nic_t *enp,
+       __in                    uint8_t dev_addr,
+       __in                    uint8_t offset,
+       __in                    uint8_t len,
+       __out_bcount(len)       uint8_t *data)
+{
+       efx_port_t *epp = &(enp->en_port);
+       efx_rc_t rc;
+       uint32_t mcdi_lower_page;
+       uint32_t mcdi_upper_page;
+
+       EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
+
+       /*
+        * Map device address to MC_CMD_GET_PHY_MEDIA_INFO pages.
+        * Offset plus length interface allows to access page 0 only.
+        * I.e. non-zero upper pages are not accessible.
+        * See SFF-8472 section 4 Memory Organization and SFF-8436 section 7.6
+        * QSFP+ Memory Map for details on how information is structured
+        * and accessible.
+        */
+       switch (epp->ep_fixed_port_type) {
+       case EFX_PHY_MEDIA_SFP_PLUS:
+               /*
+                * In accordance with SFF-8472 Diagnostic Monitoring
+                * Interface for Optical Transceivers section 4 Memory
+                * Organization two 2-wire addresses are defined.
+                */
+               switch (dev_addr) {
+               /* Base information */
+               case EFX_PHY_MEDIA_INFO_DEV_ADDR_SFP_BASE:
+                       /*
+                        * MCDI page 0 should be used to access lower
+                        * page 0 (0x00 - 0x7f) at the device address 0xA0.
+                        */
+                       mcdi_lower_page = 0;
+                       /*
+                        * MCDI page 1 should be used to access  upper
+                        * page 0 (0x80 - 0xff) at the device address 0xA0.
+                        */
+                       mcdi_upper_page = 1;
+                       break;
+               /* Diagnostics */
+               case EFX_PHY_MEDIA_INFO_DEV_ADDR_SFP_DDM:
+                       /*
+                        * MCDI page 2 should be used to access lower
+                        * page 0 (0x00 - 0x7f) at the device address 0xA2.
+                        */
+                       mcdi_lower_page = 2;
+                       /*
+                        * MCDI page 3 should be used to access upper
+                        * page 0 (0x80 - 0xff) at the device address 0xA2.
+                        */
+                       mcdi_upper_page = 3;
+                       break;
+               default:
+                       rc = ENOTSUP;
+                       goto fail1;
+               }
+               break;
+       case EFX_PHY_MEDIA_QSFP_PLUS:
+               switch (dev_addr) {
+               case EFX_PHY_MEDIA_INFO_DEV_ADDR_QSFP:
+                       /*
+                        * MCDI page -1 should be used to access lower page 0
+                        * (0x00 - 0x7f).
+                        */
+                       mcdi_lower_page = (uint32_t)-1;
+                       /*
+                        * MCDI page 0 should be used to access upper page 0
+                        * (0x80h - 0xff).
+                        */
+                       mcdi_upper_page = 0;
+                       break;
+               default:
+                       rc = ENOTSUP;
+                       goto fail1;
+               }
+               break;
+       default:
+               rc = ENOTSUP;
+               goto fail1;
+       }
+
+       if (offset < EFX_PHY_MEDIA_INFO_PAGE_SIZE) {
+               uint8_t read_len =
+                   MIN(len, EFX_PHY_MEDIA_INFO_PAGE_SIZE - offset);
+
+               rc = efx_mcdi_get_phy_media_info(enp,
+                   mcdi_lower_page, offset, read_len, data);
+               if (rc != 0)
+                       goto fail2;
+
+               data += read_len;
+               len -= read_len;
+
+               offset = 0;
+       } else {
+               offset -= EFX_PHY_MEDIA_INFO_PAGE_SIZE;
+       }
+
+       if (len > 0) {
+               EFSYS_ASSERT3U(len, <=, EFX_PHY_MEDIA_INFO_PAGE_SIZE);
+               EFSYS_ASSERT3U(offset, <, EFX_PHY_MEDIA_INFO_PAGE_SIZE);
+
+               rc = efx_mcdi_get_phy_media_info(enp,
+                   mcdi_upper_page, offset, len, data);
+               if (rc != 0)
+                       goto fail3;
+       }
+
+       return (0);
+
+fail3:
+       EFSYS_PROBE(fail3);
+fail2:
+       EFSYS_PROBE(fail2);
+fail1:
+       EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+       return (rc);
+}
 
 #endif /* EFSYS_OPT_MCDI */

Modified: head/sys/dev/sfxge/common/efx_mcdi.h
==============================================================================
--- head/sys/dev/sfxge/common/efx_mcdi.h        Wed Feb 10 10:28:33 2016        
(r295466)
+++ head/sys/dev/sfxge/common/efx_mcdi.h        Wed Feb 10 12:14:56 2016        
(r295467)
@@ -228,6 +228,14 @@ efx_mcdi_get_loopback_modes(
        __in            efx_nic_t *enp);
 #endif /* EFSYS_OPT_LOOPBACK */
 
+extern __checkReturn   efx_rc_t
+efx_mcdi_phy_module_get_info(
+       __in                    efx_nic_t *enp,
+       __in                    uint8_t dev_addr,
+       __in                    uint8_t offset,
+       __in                    uint8_t len,
+       __out_bcount(len)       uint8_t *data);
+
 #define        MCDI_IN(_emr, _type, _ofst)                                     
\
        ((_type *)((_emr).emr_in_buf + (_ofst)))
 

Modified: head/sys/dev/sfxge/common/efx_phy.c
==============================================================================
--- head/sys/dev/sfxge/common/efx_phy.c Wed Feb 10 10:28:33 2016        
(r295466)
+++ head/sys/dev/sfxge/common/efx_phy.c Wed Feb 10 12:14:56 2016        
(r295467)
@@ -560,6 +560,38 @@ efx_phy_media_type_get(
                *typep = epp->ep_fixed_port_type;
 }
 
+       __checkReturn   efx_rc_t
+efx_phy_module_get_info(
+       __in                    efx_nic_t *enp,
+       __in                    uint8_t dev_addr,
+       __in                    uint8_t offset,
+       __in                    uint8_t len,
+       __out_bcount(len)       uint8_t *data)
+{
+       efx_rc_t rc;
+
+       EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
+       EFSYS_ASSERT(data != NULL);
+
+       if ((uint32_t)offset + len > 0xff) {
+               rc = EINVAL;
+               goto fail1;
+       }
+
+       if ((rc = efx_mcdi_phy_module_get_info(enp, dev_addr,
+           offset, len, data)) != 0)
+               goto fail2;
+
+       return (0);
+
+fail2:
+       EFSYS_PROBE(fail2);
+fail1:
+       EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+       return (rc);
+}
+
 #if EFSYS_OPT_PHY_STATS
 
 #if EFSYS_OPT_NAMES

Modified: head/sys/dev/sfxge/sfxge.c
==============================================================================
--- head/sys/dev/sfxge/sfxge.c  Wed Feb 10 10:28:33 2016        (r295466)
+++ head/sys/dev/sfxge/sfxge.c  Wed Feb 10 12:14:56 2016        (r295467)
@@ -500,6 +500,30 @@ sfxge_if_ioctl(struct ifnet *ifp, unsign
        case SIOCGIFMEDIA:
                error = ifmedia_ioctl(ifp, ifr, &sc->media, command);
                break;
+#ifdef SIOCGI2C
+       case SIOCGI2C:
+       {
+               struct ifi2creq i2c;
+
+               error = copyin(ifr->ifr_data, &i2c, sizeof(i2c));
+               if (error != 0)
+                       break;
+
+               if (i2c.len > sizeof(i2c.data)) {
+                       error = EINVAL;
+                       break;
+               }
+
+               SFXGE_ADAPTER_LOCK(sc);
+               error = efx_phy_module_get_info(sc->enp, i2c.dev_addr,
+                                               i2c.offset, i2c.len,
+                                               &i2c.data[0]);
+               SFXGE_ADAPTER_UNLOCK(sc);
+               if (error == 0)
+                       error = copyout(&i2c, ifr->ifr_data, sizeof(i2c));
+               break;
+       }
+#endif
        case SIOCGPRIVATE_0:
                error = priv_check(curthread, PRIV_DRIVER);
                if (error != 0)
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to