@@ -746,59 +746,171 @@ static const char *efx_mcdi_phy_test_name(struct efx_nic *efx,
746
746
return NULL ;
747
747
}
748
748
749
- #define SFP_PAGE_SIZE 128
750
- #define SFP_NUM_PAGES 2
751
- static int efx_mcdi_phy_get_module_eeprom (struct efx_nic * efx ,
752
- struct ethtool_eeprom * ee , u8 * data )
749
+ #define SFP_PAGE_SIZE 128
750
+ #define SFF_DIAG_TYPE_OFFSET 92
751
+ #define SFF_DIAG_ADDR_CHANGE BIT(2)
752
+ #define SFF_8079_NUM_PAGES 2
753
+ #define SFF_8472_NUM_PAGES 4
754
+ #define SFF_8436_NUM_PAGES 5
755
+ #define SFF_DMT_LEVEL_OFFSET 94
756
+
757
+ /** efx_mcdi_phy_get_module_eeprom_page() - Get a single page of module eeprom
758
+ * @efx: NIC context
759
+ * @page: EEPROM page number
760
+ * @data: Destination data pointer
761
+ * @offset: Offset in page to copy from in to data
762
+ * @space: Space available in data
763
+ *
764
+ * Return:
765
+ * >=0 - amount of data copied
766
+ * <0 - error
767
+ */
768
+ static int efx_mcdi_phy_get_module_eeprom_page (struct efx_nic * efx ,
769
+ unsigned int page ,
770
+ u8 * data , ssize_t offset ,
771
+ ssize_t space )
753
772
{
754
773
MCDI_DECLARE_BUF (outbuf , MC_CMD_GET_PHY_MEDIA_INFO_OUT_LENMAX );
755
774
MCDI_DECLARE_BUF (inbuf , MC_CMD_GET_PHY_MEDIA_INFO_IN_LEN );
756
775
size_t outlen ;
757
- int rc ;
758
776
unsigned int payload_len ;
759
- unsigned int space_remaining = ee -> len ;
760
- unsigned int page ;
761
- unsigned int page_off ;
762
777
unsigned int to_copy ;
763
- u8 * user_data = data ;
778
+ int rc ;
764
779
765
- BUILD_BUG_ON (SFP_PAGE_SIZE * SFP_NUM_PAGES != ETH_MODULE_SFF_8079_LEN );
780
+ if (offset > SFP_PAGE_SIZE )
781
+ return - EINVAL ;
766
782
767
- page_off = ee -> offset % SFP_PAGE_SIZE ;
768
- page = ee -> offset / SFP_PAGE_SIZE ;
783
+ to_copy = min (space , SFP_PAGE_SIZE - offset );
769
784
770
- while (space_remaining && (page < SFP_NUM_PAGES )) {
771
- MCDI_SET_DWORD (inbuf , GET_PHY_MEDIA_INFO_IN_PAGE , page );
785
+ MCDI_SET_DWORD (inbuf , GET_PHY_MEDIA_INFO_IN_PAGE , page );
786
+ rc = efx_mcdi_rpc_quiet (efx , MC_CMD_GET_PHY_MEDIA_INFO ,
787
+ inbuf , sizeof (inbuf ),
788
+ outbuf , sizeof (outbuf ),
789
+ & outlen );
772
790
773
- rc = efx_mcdi_rpc (efx , MC_CMD_GET_PHY_MEDIA_INFO ,
774
- inbuf , sizeof (inbuf ),
775
- outbuf , sizeof (outbuf ),
776
- & outlen );
777
- if (rc )
778
- return rc ;
791
+ if (rc )
792
+ return rc ;
793
+
794
+ if (outlen < (MC_CMD_GET_PHY_MEDIA_INFO_OUT_DATA_OFST +
795
+ SFP_PAGE_SIZE ))
796
+ return - EIO ;
797
+
798
+ payload_len = MCDI_DWORD (outbuf , GET_PHY_MEDIA_INFO_OUT_DATALEN );
799
+ if (payload_len != SFP_PAGE_SIZE )
800
+ return - EIO ;
779
801
780
- if (outlen < (MC_CMD_GET_PHY_MEDIA_INFO_OUT_DATA_OFST +
781
- SFP_PAGE_SIZE ))
782
- return - EIO ;
802
+ memcpy (data , MCDI_PTR (outbuf , GET_PHY_MEDIA_INFO_OUT_DATA ) + offset ,
803
+ to_copy );
783
804
784
- payload_len = MCDI_DWORD (outbuf ,
785
- GET_PHY_MEDIA_INFO_OUT_DATALEN );
786
- if (payload_len != SFP_PAGE_SIZE )
787
- return - EIO ;
805
+ return to_copy ;
806
+ }
788
807
789
- /* Copy as much as we can into data */
790
- payload_len -= page_off ;
791
- to_copy = (space_remaining < payload_len ) ?
792
- space_remaining : payload_len ;
808
+ static int efx_mcdi_phy_get_module_eeprom_byte (struct efx_nic * efx ,
809
+ unsigned int page ,
810
+ u8 byte )
811
+ {
812
+ int rc ;
813
+ u8 data ;
793
814
794
- memcpy (user_data ,
795
- MCDI_PTR (outbuf , GET_PHY_MEDIA_INFO_OUT_DATA ) + page_off ,
796
- to_copy );
815
+ rc = efx_mcdi_phy_get_module_eeprom_page (efx , page , & data , byte , 1 );
816
+ if (rc == 1 )
817
+ return data ;
818
+
819
+ return rc ;
820
+ }
821
+
822
+ static int efx_mcdi_phy_diag_type (struct efx_nic * efx )
823
+ {
824
+ /* Page zero of the EEPROM includes the diagnostic type at byte 92. */
825
+ return efx_mcdi_phy_get_module_eeprom_byte (efx , 0 ,
826
+ SFF_DIAG_TYPE_OFFSET );
827
+ }
797
828
798
- space_remaining -= to_copy ;
799
- user_data += to_copy ;
800
- page_off = 0 ;
801
- page ++ ;
829
+ static int efx_mcdi_phy_sff_8472_level (struct efx_nic * efx )
830
+ {
831
+ /* Page zero of the EEPROM includes the DMT level at byte 94. */
832
+ return efx_mcdi_phy_get_module_eeprom_byte (efx , 0 ,
833
+ SFF_DMT_LEVEL_OFFSET );
834
+ }
835
+
836
+ static u32 efx_mcdi_phy_module_type (struct efx_nic * efx )
837
+ {
838
+ struct efx_mcdi_phy_data * phy_data = efx -> phy_data ;
839
+
840
+ if (phy_data -> media != MC_CMD_MEDIA_QSFP_PLUS )
841
+ return phy_data -> media ;
842
+
843
+ /* A QSFP+ NIC may actually have an SFP+ module attached.
844
+ * The ID is page 0, byte 0.
845
+ */
846
+ switch (efx_mcdi_phy_get_module_eeprom_byte (efx , 0 , 0 )) {
847
+ case 0x3 :
848
+ return MC_CMD_MEDIA_SFP_PLUS ;
849
+ case 0xc :
850
+ case 0xd :
851
+ return MC_CMD_MEDIA_QSFP_PLUS ;
852
+ default :
853
+ return 0 ;
854
+ }
855
+ }
856
+
857
+ static int efx_mcdi_phy_get_module_eeprom (struct efx_nic * efx ,
858
+ struct ethtool_eeprom * ee , u8 * data )
859
+ {
860
+ int rc ;
861
+ ssize_t space_remaining = ee -> len ;
862
+ unsigned int page_off ;
863
+ bool ignore_missing ;
864
+ int num_pages ;
865
+ int page ;
866
+
867
+ switch (efx_mcdi_phy_module_type (efx )) {
868
+ case MC_CMD_MEDIA_SFP_PLUS :
869
+ num_pages = efx_mcdi_phy_sff_8472_level (efx ) > 0 ?
870
+ SFF_8472_NUM_PAGES : SFF_8079_NUM_PAGES ;
871
+ page = 0 ;
872
+ ignore_missing = false;
873
+ break ;
874
+ case MC_CMD_MEDIA_QSFP_PLUS :
875
+ num_pages = SFF_8436_NUM_PAGES ;
876
+ page = -1 ; /* We obtain the lower page by asking for -1. */
877
+ ignore_missing = true; /* Ignore missing pages after page 0. */
878
+ break ;
879
+ default :
880
+ return - EOPNOTSUPP ;
881
+ }
882
+
883
+ page_off = ee -> offset % SFP_PAGE_SIZE ;
884
+ page += ee -> offset / SFP_PAGE_SIZE ;
885
+
886
+ while (space_remaining && (page < num_pages )) {
887
+ rc = efx_mcdi_phy_get_module_eeprom_page (efx , page ,
888
+ data , page_off ,
889
+ space_remaining );
890
+
891
+ if (rc > 0 ) {
892
+ space_remaining -= rc ;
893
+ data += rc ;
894
+ page_off = 0 ;
895
+ page ++ ;
896
+ } else if (rc == 0 ) {
897
+ space_remaining = 0 ;
898
+ } else if (ignore_missing && (page > 0 )) {
899
+ int intended_size = SFP_PAGE_SIZE - page_off ;
900
+
901
+ space_remaining -= intended_size ;
902
+ if (space_remaining < 0 ) {
903
+ space_remaining = 0 ;
904
+ } else {
905
+ memset (data , 0 , intended_size );
906
+ data += intended_size ;
907
+ page_off = 0 ;
908
+ page ++ ;
909
+ rc = 0 ;
910
+ }
911
+ } else {
912
+ return rc ;
913
+ }
802
914
}
803
915
804
916
return 0 ;
@@ -807,16 +919,42 @@ static int efx_mcdi_phy_get_module_eeprom(struct efx_nic *efx,
807
919
static int efx_mcdi_phy_get_module_info (struct efx_nic * efx ,
808
920
struct ethtool_modinfo * modinfo )
809
921
{
810
- struct efx_mcdi_phy_data * phy_cfg = efx -> phy_data ;
922
+ int sff_8472_level ;
923
+ int diag_type ;
811
924
812
- switch (phy_cfg -> media ) {
925
+ switch (efx_mcdi_phy_module_type ( efx ) ) {
813
926
case MC_CMD_MEDIA_SFP_PLUS :
814
- modinfo -> type = ETH_MODULE_SFF_8079 ;
815
- modinfo -> eeprom_len = ETH_MODULE_SFF_8079_LEN ;
816
- return 0 ;
927
+ sff_8472_level = efx_mcdi_phy_sff_8472_level (efx );
928
+
929
+ /* If we can't read the diagnostics level we have none. */
930
+ if (sff_8472_level < 0 )
931
+ return - EOPNOTSUPP ;
932
+
933
+ /* Check if this module requires the (unsupported) address
934
+ * change operation.
935
+ */
936
+ diag_type = efx_mcdi_phy_diag_type (efx );
937
+
938
+ if ((sff_8472_level == 0 ) ||
939
+ (diag_type & SFF_DIAG_ADDR_CHANGE )) {
940
+ modinfo -> type = ETH_MODULE_SFF_8079 ;
941
+ modinfo -> eeprom_len = ETH_MODULE_SFF_8079_LEN ;
942
+ } else {
943
+ modinfo -> type = ETH_MODULE_SFF_8472 ;
944
+ modinfo -> eeprom_len = ETH_MODULE_SFF_8472_LEN ;
945
+ }
946
+ break ;
947
+
948
+ case MC_CMD_MEDIA_QSFP_PLUS :
949
+ modinfo -> type = ETH_MODULE_SFF_8436 ;
950
+ modinfo -> eeprom_len = ETH_MODULE_SFF_8436_LEN ;
951
+ break ;
952
+
817
953
default :
818
954
return - EOPNOTSUPP ;
819
955
}
956
+
957
+ return 0 ;
820
958
}
821
959
822
960
static const struct efx_phy_operations efx_mcdi_phy_ops = {
0 commit comments